diff -urN cahier-de-prepa8.1.1/agenda.php cahier-de-prepa9.0.0/agenda.php
--- cahier-de-prepa8.1.1/agenda.php	2018-10-15 17:50:34.840788232 +0200
+++ cahier-de-prepa9.0.0/agenda.php	2019-08-25 01:59:46.442156393 +0200
@@ -71,7 +71,7 @@
                             DATE_FORMAT(debut,'%d/%m/%Y') AS jd, DATE_FORMAT(fin,'%d/%m/%Y') AS jf,
                             DATE_FORMAT(debut,'%kh%i') AS hd, DATE_FORMAT(fin,'%kh%i') AS hf,
                             DATEDIFF(debut,'$deb')+1 AS njd, DATEDIFF(fin,'$deb')+1 AS njf
-                            FROM agenda AS a JOIN `agenda-types` AS t ON a.type = t.id LEFT JOIN matieres AS m ON a.matiere = m.id
+                            FROM agenda AS a LEFT JOIN `agenda-types` AS t ON a.type = t.id LEFT JOIN matieres AS m ON a.matiere = m.id
                             WHERE debut < '$deb' + INTERVAL ".($j1+7*$nbs)." DAY AND fin >= '$deb' - INTERVAL $j1 DAY
                             ORDER BY fin,debut");
 if ( $resultat->num_rows )  {
@@ -287,7 +287,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Administratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Agenda désactivé</option>';
   $p = $protection;
diff -urN cahier-de-prepa8.1.1/agenda-types.php cahier-de-prepa9.0.0/agenda-types.php
--- cahier-de-prepa8.1.1/agenda-types.php	2018-11-06 10:19:04.699957078 +0100
+++ cahier-de-prepa9.0.0/agenda-types.php	2019-08-05 01:36:06.765303979 +0200
@@ -12,7 +12,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
diff -urN cahier-de-prepa8.1.1/ajax.php cahier-de-prepa9.0.0/ajax.php
--- cahier-de-prepa8.1.1/ajax.php	2018-11-10 22:28:33.857051342 +0100
+++ cahier-de-prepa9.0.0/ajax.php	2019-08-28 14:22:21.867100664 +0200
@@ -16,15 +16,7 @@
 
 // Demande de déconnexion
 if ( $action == 'deconnexion' )  {
-  // Écriture de la déconnexion dans le fichier de log, sauf si la session a
-  // été perdue parce qu'effacée du serveur
-  if ( isset($_SESSION['login']) )
-    logconnect(3,$_SESSION['login']);
-  // Suppression du cookie et des données de session
-  $_SESSION = array();
-  setcookie(session_name(),'',time()-3600);
-  setcookie('loginpermanent','',time()-3600);
-  session_regenerate_id(true);
+  suppression_session();
   // Recharge immédiate, donc besoin de $_SESSION['message']
   exit($_SESSION['message'] = '{"etat":"ok","message":"Déconnexion réussie"}');
 }
@@ -35,23 +27,27 @@
 ///////////////////////
 // Envoi de courriel //
 ///////////////////////
-if ( ( $action == 'courriel' ) && connexionlight() && $_SESSION['mailenvoi'] && isset($_REQUEST['id-copie']) && isset($_REQUEST['sujet']) && isset($_REQUEST['texte']) )  {
-
+if ( ( $action == 'courriel' ) && connexionlight() && isset($_REQUEST['id-copie']) && isset($_REQUEST['sujet']) && isset($_REQUEST['texte']) )  {
+  // Envoi possible seulement si autorisé
+  $mysqli = connectsql();
+  $resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+  if ( ( $aut_envoi = $resultat->fetch_row()[0] >> 4*($autorisation-2) & 15 ) == 0 )
+    exit('{"etat":"nok","message":"L\'envoi de courriel n\'est pas autorisé."}');
+  $aut_dest = implode(',',array_keys(str_split('00'.strrev(decbin($aut_envoi))),1));
+  $resultat->free();
   // Vérification des données
-  if ( !strlen($sujet = $_REQUEST['sujet']) )
+  if ( !($sujet = $_REQUEST['sujet']) )
     exit('{"etat":"nok","message":"Pas de sujet : courriel non envoyé"}');
-  elseif ( !strlen($texte = $_REQUEST['texte']) )
+  elseif ( !($texte = $_REQUEST['texte']) )
     exit('{"etat":"nok","message":"Pas de texte : courriel non envoyé"}');
   // Vérification de l'adresse électronique
-  $mysqli = connectsql();
   $resultat = $mysqli->query("SELECT mailexp, mail FROM utilisateurs WHERE id = ${_SESSION['id']}");
   $u = $resultat->fetch_assoc();
   $resultat->free();
-  if ( !strlen($u['mailexp']) || !filter_var($u['mail'],FILTER_VALIDATE_EMAIL) )
+  if ( !$u['mailexp'] || !filter_var($u['mail'],FILTER_VALIDATE_EMAIL) )
     exit('{"etat":"nok","message":"Compte mal réglé&nbsp;: nom ou adresse d\'expédition manquants"}');
   // Récupération des destinataires, comptes valides uniquement
-  $resultat = $mysqli->query("SELECT id, IF(LENGTH(nom),CONCAT(nom,' ',prenom),login) AS nom, mail
-                              FROM utilisateurs WHERE mail > '' AND mdp > '0' AND id != ${_SESSION['id']} ORDER BY autorisation DESC, nom");
+  $resultat = $mysqli->query("SELECT id, mail, mailexp FROM utilisateurs WHERE mail > '' AND mdp > '0' AND id != ${_SESSION['id']} AND FIND_IN_SET(autorisation,'$aut_dest') ORDER BY autorisation DESC, nom");
   $mysqli->close();
   while ( $r = $resultat->fetch_assoc() )
     $utilisateurs[$r['id']] = $r;
@@ -60,28 +56,28 @@
   $ids = explode(',',$_REQUEST['id-copie']);
   foreach ( $ids as $i )
     if ( isset($utilisateurs[$i]) )  {
-      $dests .= '=?UTF-8?B?'.base64_encode($utilisateurs[$i]['nom']).'?= <'.$utilisateurs[$i]['mail'].'>, ';
+      $dests .= '=?UTF-8?B?'.base64_encode($utilisateurs[$i]['mailexp']).'?= <'.$utilisateurs[$i]['mail'].'>, ';
       unset($utilisateurs[$i]);
     }
-  if ( !strlen($dests) )
+  if ( !$dests )
     exit('{"etat":"nok","message":"Pas de destinataire valide : courriel non envoyé"}');
   // Fabrication du mail
   $dests = substr($dests,0,-2);
   $bcc = ( isset($_REQUEST['copie']) ) ? "${u['mailexp']} <${u['mail']}>, " : '';
-  if ( strlen($_REQUEST['id-bcc']) )
+  if ( $_REQUEST['id-bcc'] )
     $ids = explode(',',$_REQUEST['id-bcc']);
     foreach ( $ids as $i )
       if ( isset($utilisateurs[$i]) )  {
-        $bcc .= '=?UTF-8?B?'.base64_encode($utilisateurs[$i]['nom']).'?= <'.$utilisateurs[$i]['mail'].'>, ';
+        $bcc .= '=?UTF-8?B?'.base64_encode($utilisateurs[$i]['mailexp']).'?= <'.$utilisateurs[$i]['mail'].'>, ';
         unset($utilisateurs[$i]);
       }
-  $bcc = ( strlen($bcc) ) ? 'Bcc: '.substr($bcc,0,-2) : '';
+  $bcc = ( $bcc ) ? 'Bcc: '.substr($bcc,0,-2) : '';
   mail($dests,'=?UTF-8?B?'.base64_encode($sujet).'?=',$texte,'From: =?UTF-8?B?'.base64_encode($u['mailexp']).'?= <nepasrepondre'.strstr($mailadmin,'@').">\r\nReply-To: =?UTF-8?B?".base64_encode($u['mailexp'])."?= <${u['mail']}>\r\nContent-type: text/plain; charset=UTF-8\r\n$bcc","-f${u['mail']}");
   // Message de confirmation d'envoi
   $n1 = substr_count($dests,'<');
   $n2 = substr_count($bcc,'<') - isset($_REQUEST['copie']);
   if ( $n2 )
-    $message = 'La courriel a été envoyé à '.($n1+$n2).' destinataires (dont '.$n2.' en copie cachée).';
+    $message = 'Le courriel a été envoyé à '.($n1+$n2).' destinataires (dont '.$n2.' en copie cachée).';
   else
     $message = ( $n1 > 1 ) ? "Le courriel a été envoyé à $n1 destinataires." : 'Le courriel a été envoyé à 1 destinataire.';
   exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"$message\"}");
@@ -95,123 +91,194 @@
 
   // Spécifications pour les manipulations de caractères sur 2 octets (accents)
   mb_internal_encoding('UTF-8');
-  // Vérification obligatoire du mot de passe
+  // Vérification obligatoire du mot de passe et récupération des données de l'utilisateur
   if ( !isset($_REQUEST['mdp']) )
     exit('{"etat":"nok","message":"Mot de passe incorrect"}');
-  // L'adresse électronique sert dans les cas 1 et 4
   $mysqli = connectsql(true);
-  $resultat = $mysqli->query("SELECT mdp, mail FROM utilisateurs WHERE id = ${_SESSION['id']}");
+  $resultat = $mysqli->query("SELECT * FROM utilisateurs WHERE id = ${_SESSION['id']}");
   $r = $resultat->fetch_assoc();
   $resultat->free();
-  if ( ( sha1($mdp.$_REQUEST['mdp']) != $r['mdp'] ) && ( sha1($_REQUEST['mdp']) != $r['mdp'] ) )
+  if ( sha1($mdp.$_REQUEST['mdp']) != $r['mdp'] )
     exit('{"etat":"nok","message":"Mot de passe incorrect"}');
   // Passage de la connexion light à normale si besoin
-  if ( $_SESSION['light'] )  {
-    $_SESSION['light'] = false;
-    // Écriture de la connexion dans le fichier de log
-    logconnect(5,$_SESSION['login']);
+  if ( $_SESSION['light'] )
+    enregistre_session(false,false,$r['timeout']);
+  
+  // Fonction de fabrication de la partie modifiante de la requête
+  function fabriqueupdate($requete,$mysqli)  {
+    $chaine = '';
+    foreach ($requete as $champ=>$val)
+      $chaine .= ",$champ = '".$mysqli->real_escape_string($val).'\'';
+    return substr($chaine,1);
   }
   
   // Premier cadre de modifications de prefs.php : indentité
-  if ( ( $_REQUEST['id'] == 1 ) && isset($_REQUEST['prenom']) && isset($_REQUEST['nom']) && isset($_REQUEST['mail1']) && isset($_REQUEST['mail2']) )  {
-    $requete_mail = '';
-    if ( !strlen($prenom = trim($_REQUEST['prenom'])) || !strlen($nom = trim($_REQUEST['nom'])) || !strlen($mail = mb_strtolower(trim($_REQUEST['mail1']))) )
-      exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Le prénom, le nom et l\'adresse électronique doivent rester non vides."}');
-    if ( ( $mail != $r['mail'] ) && strlen($_REQUEST['mail2']) )  {
-      if ( !filter_var($mail,FILTER_VALIDATE_EMAIL) )
-        exit('{"etat":"nok","message":"Adresse électronique non valide"}');
-      if ( $mail != mb_strtolower(trim($_REQUEST['mail2'])) )
-        exit('{"etat":"nok","message":"Adresses électroniques différentes"}');
-      // Vérification que l'adresse n'existe pas déjà
-      $resultat = $mysqli->query("SELECT GROUP_CONCAT(mail) FROM utilisateurs WHERE id != ${_SESSION['id']} AND mail > ''");
-      $r = $resultat->fetch_row();
-      $resultat->free();
-      if ( in_array($mail,explode(',',$r[0])) )
-        exit('{"etat":"nok","message":"Adresse électronique non disponible"}');
-      $requete_mail = ', mail = \''.$mysqli->real_escape_string($mail).'\'';
-    }
-    // Nettoyage des données envoyées
-    $prenom = mb_convert_case(strip_tags($mysqli->real_escape_string($prenom)),MB_CASE_TITLE);
-    $nom = mb_convert_case(strip_tags($mysqli->real_escape_string($nom)),MB_CASE_TITLE);
-    if ( requete('utilisateurs',"UPDATE utilisateurs SET nom = '$nom', prenom = '$prenom'$requete_mail WHERE id = ${_SESSION['id']}",$mysqli) )
+  if ( ( $_REQUEST['id'] == 1 ) && isset($_REQUEST['prenom']) && isset($_REQUEST['nom']) )  {
+    // Vérification et nettoyage des données
+    if ( !($prenom = mb_convert_case(strip_tags(trim($_REQUEST['prenom'])),MB_CASE_TITLE)) || !($nom = mb_convert_case(strip_tags(trim($_REQUEST['nom'])),MB_CASE_TITLE)) )
+      exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Le prénom et le nom doivent rester non vides."}');
+    // Construction de la requête
+    $requete = array();
+    if ( $prenom != $r['prenom'] )
+      $requete['prenom'] = $prenom;
+    if ( $nom != $r['nom'] )
+      $requete['nom'] = $nom;
+    if ( !$requete )
+      exit('{"etat":"nok","message":"Aucune modification à faire"}');
+    if ( requete('utilisateurs','UPDATE utilisateurs SET ' .fabriqueupdate($requete,$mysqli) . " WHERE id = ${_SESSION['id']}",$mysqli) )  {
+      // Si interface globale activée, mise à jour
+      if ( $interfaceglobale )  {
+        include("${interfaceglobale}majutilisateurs.php");
+        majutilisateurs($_SESSION['id'],$requete);
+      }
       exit('{"etat":"ok","message":"Vos préférences ont été modifiées."}');
+    }
     exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
   
   // Deuxième cadre de modifications de prefs.php : mot de passe
   if ( ( $_REQUEST['id'] == 2 ) && isset($_REQUEST['mdp1']) && isset($_REQUEST['mdp2']) )  {
-    if ( !strlen($mdp1 = $_REQUEST['mdp1']) || ( $mdp1 != $_REQUEST['mdp2'] ) )
+    if ( !($mdp1 = $_REQUEST['mdp1']) || ( $mdp1 != $_REQUEST['mdp2'] ) )
       exit('{"etat":"nok","message":"Nouveau mot de passe et confirmation différents"}');
-    // Token de connexion automatique
-    if ( strlen($permconn = $_SESSION['permconn']) )
+    $requete = array('mdp'=>sha1($mdp.$mdp1));
+    // Token de connexion automatique à renouveler si existant
+    if ( $_SESSION['permconn'] )  {
+      $permconn = '';
       for ( $i = 0; $i < 10; $i++ )
         $permconn .= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[random_int(0,61)];
-    if( requete('utilisateurs','UPDATE utilisateurs SET mdp = \''.sha1($mdp.$mdp1)."', permconn = '$permconn' WHERE id = ${_SESSION['id']}",$mysqli) )  {
-      if ( strlen($permconn) )
-        setcookie('loginpermanent',$permconn,time()+31536000);
-      exit('{"etat":"ok","message":"Votre mot de passe a été modifié."}');
+      $requete['permconn'] = $permconn;
+    }
+    if ( !$requete )
+      exit('{"etat":"nok","message":"Aucune modification à faire"}');
+    # Éxécution
+    if ( requete('utilisateurs','UPDATE utilisateurs SET ' .fabriqueupdate($requete,$mysqli) . " WHERE id = ${_SESSION['id']}",$mysqli) )  {
+      if ( isset($permconn) )
+        setcookie('CDP_SESSION_PERM',$permconn,time()+31536000,$chemin,$domaine,true);
+      // Si interface globale activée, mise à jour
+      if ( $interfaceglobale )  {
+        include("${interfaceglobale}majutilisateurs.php");
+        majutilisateurs($_SESSION['id'],$requete);
+      }
+      exit($_SESSION['message'] = '{"etat":"ok","message":"Votre mot de passe a été modifié."}');
     }
     exit('{"etat":"nok","message":"Votre mot de passe n\'a pas été modifié. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 
-  // Troisième cadre de modifications de prefs.php : connexion
-  if ( ( $_REQUEST['id'] == 3 ) && isset($_REQUEST['login']) && isset($_REQUEST['timeout']) && ctype_digit($timeout = $_REQUEST['timeout']) )  {
-    $requete_login = '';
-    if ( !strlen($login = mb_strtolower(str_replace(' ','_',strip_tags(trim($_REQUEST['login']))))) )
+  // Troisième cadre de modifications de prefs.php : adresse électronique
+  if ( ( $_REQUEST['id'] == 3 ) && isset($_REQUEST['mail']) )  {
+    // Vérification et nettoyage des données
+    if ( !($mail = filter_var(mb_strtolower(trim($_REQUEST['mail'])),FILTER_VALIDATE_EMAIL)) )
+      exit('{"etat":"nok","message":"L\'adresse électronique doit être valide et non vide."}');
+    // Vérification que l'adresse n'est pas déjà utilisée
+    $resultat = $mysqli->query('SELECT id FROM utilisateurs WHERE mail = \''.$mysqli->real_escape_string($mail)."' AND id != ${_SESSION['id']}");
+    if ( $resultat->num_rows )
+      exit('{"etat":"nok","message":"Adresse électronique non disponible"}');
+    // Si pas de code de confirmation : envoi de courriel
+    if ( !isset($_REQUEST['confirmation']) )  {
+      // On ajoute 15 minutes au temps utilisé : de xh00 à xh45,
+      // on a jusqu'à (x+1)h, de xh45 à (x+1)h on a jusqu'à (x+2)h
+      $t = time() + 900;
+      $p = substr(sha1($chemin.$mdp.date('Y-m-d-H',$t).$mail),0,8);
+      mail($mail,'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Changement d\'adresse électronique').'?=',
+"Bonjour
+
+Vous avez demandé à modifier l'adresse électronique liée à votre compte sur le Cahier de Prépa <https://$domaine$chemin>.
+
+Cette demande nécessite la vérification que vous possédez l'adresse à laquelle vous recevez ce courriel.
+
+Pour ce faire, vous devez copier, sur la page qui a généré ce courriel, le code suivant :
+
+     $p
+
+Ce code est valable jusqu'à ".date('G\h00',$t+3600).'.
+
+Si cette demande ne vient pas de vous, merci d\'ignorer ce courriel et éventuellement de le signaler à l\'administrateur en répondant à ce courriel.
+
+Cordialement,
+-- 
+Cahier de Prépa
+  ','From: =?UTF-8?B?'.base64_encode('Cahier de Prépa')."?= <$mailadmin>\r\nContent-type: text/plain; charset=UTF-8","-f$mailadmin");
+      exit('{"etat":"confirm_mail","message":"<strong>Un courriel vient de vous être envoyé à l\'adresse <code>'.$mail.'</code>.</strong><br>Il contient un code, valable jusqu\'à '.date('G\h00',$t+3600).', que vous devez copier-coller ci-dessous pour réaliser l\'opération.<br>Si vous ne voyez rien, pensez à regarder dans les courriels marqués comme spam. Certains serveurs retardent jusqu\'à 10 minutes l\'arrivée des messages, normalement la première fois uniquement."}');
+    }
+    // $_REQUEST['p'] est obligatoirement défini. Il s'agit du sha1 de $chemin.$mdp.date('Y-m-d-H').$mail
+    if ( ( ($p=$_REQUEST['confirmation']) != substr(sha1($chemin.$mdp.date('Y-m-d-H').$mail),0,8) ) && ( $p != substr(sha1($chemin.$mdp.date('Y-m-d-H',time()+900).$mail),0,8) ) )
+      exit('{"etat":"nok","message":"Le code saisi n\'est pas correct. Si vous avez dépassé le délai, vous devez recommencer la procédure."}');
+    // Modification
+    if ( requete('utilisateurs','UPDATE utilisateurs SET mail = \'' .$mysqli->real_escape_string($mail)."' WHERE id = ${_SESSION['id']}",$mysqli) )  {
+      // Si interface globale activée, mise à jour
+      if ( $interfaceglobale )  {
+        include("${interfaceglobale}majutilisateurs.php");
+        majutilisateurs($_SESSION['id'],array('mail'=>$mail));
+      }
+      exit($_SESSION['message'] = '{"etat":"ok","message":"Vos préférences ont été modifiées."}');
+    }
+    exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+  }
+  
+  // Quatrième cadre de modifications de prefs.php : connexion
+  if ( ( $_REQUEST['id'] == 4 ) && isset($_REQUEST['login']) && isset($_REQUEST['timeout']) && ctype_digit($timeout = $_REQUEST['timeout']) )  {
+    if ( !($login = mb_strtolower(str_replace(' ','_',strip_tags(trim($_REQUEST['login']))))) )
       exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. L\'identifiant doit être non vide."}');
+    $requete = array();
     if ( $login != $_SESSION['login'] )  {
       // Vérification que le login n'existe pas déjà
-      $resultat = $mysqli->query("SELECT GROUP_CONCAT(login) FROM utilisateurs WHERE id != ${_SESSION['id']}");
-      $r = $resultat->fetch_row();
-      $resultat->free();
-      if ( in_array($login,explode(',',$r[0])) )
-        exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. L\'identifiant saisi est déjà utilisé."}');
-      $requete_login = ', login = \''.$mysqli->real_escape_string($login).'\'';
+      $resultat = $mysqli->query('SELECT id FROM utilisateurs WHERE login = '.$mysqli->real_escape_string($login)." AND id != ${_SESSION['id']}");
+      if ( $resultat->num_rows )
+        exit('{"etat":"nok","message":"Adresse électronique non disponible"}');
+      $requete['login'] = $login;
     }
-    // Token de connexion automatique
-    if ( !strlen($permconn = $_SESSION['permconn']) && isset($_REQUEST['permconn']) )
+    // Token de connexion automatique à ajouter si non déjà présent et demandé
+    if ( !$_SESSION['permconn'] && isset($_REQUEST['permconn']) )  {
+      $permconn = '';
       for ( $i = 0; $i < 10; $i++ )
         $permconn .= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[random_int(0,61)];
-    elseif ( !isset($_REQUEST['permconn']) )
-      $permconn = '';
-    $timeout = ( $timeout > 15 ) ? $timeout : 900;
-    if ( requete('utilisateurs',"UPDATE utilisateurs SET timeout = $timeout$requete_login, permconn = '$permconn' WHERE id = ${_SESSION['id']}",$mysqli) )  {
+      $requete['permconn'] = $permconn;
+    }
+    elseif ( $_SESSION['permconn'] && !isset($_REQUEST['permconn']) )
+      $requete['permconn'] = '';
+    // Timeout
+    if ( ( $timeout = ( $timeout > 15 ) ? $timeout : 900 ) != $_SESSION['timeout'] )
+      $requete['timeout'] = $timeout;
+    if ( !$requete )
+      exit('{"etat":"nok","message":"Aucune modification à faire"}');
+    # Éxécution
+    if ( requete('utilisateurs','UPDATE utilisateurs SET ' .fabriqueupdate($requete,$mysqli) . " WHERE id = ${_SESSION['id']}",$mysqli) )  {
       // Mise à jour des données de session et cookies
-      $_SESSION['timeout'] = $timeout;
-      $_SESSION['time'] = time()+$_SESSION['timeout'];
-      $_SESSION['permconn'] = $permconn;
-      setcookie('loginpermanent',$permconn,( strlen($permconn) ) ? time()+31536000 : time()-3600);
-      if ( strlen($requete_login) )
+      if ( isset($requete['login']) )
         $_SESSION['login'] = $login;
+      if ( isset($requete['timeout']) )  {
+        $_SESSION['timeout'] = $timeout;
+        $_SESSION['time'] = time()+$_SESSION['timeout'];
+      }
+      if ( isset($requete['permconn']) )  {
+        $_SESSION['permconn'] = $permconn;
+        setcookie('CDP_SESSION_PERM',$permconn,( $permconn ) ? time()+31536000 : time()-3600,$chemin,$domaine,true);
+      }
+      // Si interface globale activée, mise à jour
+      if ( $interfaceglobale )  {
+        include("${interfaceglobale}majutilisateurs.php");
+        majutilisateurs($_SESSION['id'],$requete);
+      }
       exit('{"etat":"ok","message":"Vos préférences de connexion ont été modifiées."}');
     }
     exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 
-  // Quatrième cadre de modifications de prefs.php : envoi de courriel
-  if ( ( $_REQUEST['id'] == 4 ) && isset($_REQUEST['mailexp']) )  {
-    // Compte élève : modification possible seulement si envoi de courriel déjà possible
-    if ( $autorisation == 2 )  {
-      if ( $_SESSION['mailenvoi'] == 0 )
-        exit('{"etat":"nok","message":"Ce réglage n\'est pas autorisé."}');
-      if ( !strlen($mailexp = strip_tags(trim($_REQUEST['mailexp']))) )
-        exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Le nom d\'expéditeur doit être non vide."}');
-      if( requete('utilisateurs','UPDATE utilisateurs SET mailexp = \''.$mysqli->real_escape_string($mailexp).'\', mailcopie = '.intval(isset($_REQUEST['mailcopie']))." WHERE id = ${_SESSION['id']}",$mysqli) )
-        exit('{"etat":"ok","message":"Vos préférences d\'envoi de mail ont été modifiées."}');
-      exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}' );
-    }
-    // Autres types de comptes
-    // Interdiction de vider mailexp si on souhaite garder l'envoi possible
-    $mailexp = strip_tags(trim($_REQUEST['mailexp']));
-    if ( ( $mailenvoi = intval(isset($_REQUEST['mailenvoi'])) ) && !strlen($mailexp) )
+  // Cinquième cadre de modifications de prefs.php : envoi de courriel
+  if ( ( $_REQUEST['id'] == 5 ) && isset($_REQUEST['mailexp']) )  {
+    // Réglages disponibles seulement si autorisé globalement
+    $resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+    if ( !( $resultat->fetch_row()[0] >> 4*($autorisation-2) & 15 ) )
+      exit('{"etat":"nok","message":"Ce réglage n\'est pas autorisé.'.$a.'-'.$autorisation.'"}');
+    $resultat->free();
+    // Pas d'envoi si l'adresse électronique est vide
+    if ( !$r['mail'] )
+      exit('{"etat":"nok","message":"Vous ne pourrez pas envoyer de courriels sans adresse électronique. Vous devez la saisir avant de modifier ces préférences."}');
+    if ( !( $mailexp = $mysqli->real_escape_string(strip_tags(trim($_REQUEST['mailexp']))) ) )
       exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Le nom d\'expéditeur doit être non vide."}');
-    // Interdiction d'envoyer si l'adresse électronique est vide
-    if ( $mailenvoi && !strlen($r['mail']) )
-      exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Il est impossible d\'envoyer des courriels sans adresse électronique."}');
-    if ( requete('utilisateurs','UPDATE utilisateurs SET mailexp = \''.$mysqli->real_escape_string($mailexp)."', mailenvoi = $mailenvoi, mailcopie = ".intval(isset($_REQUEST['mailcopie'])).', mailliste = '.intval(isset($_REQUEST['mailliste']))." WHERE id = ${_SESSION['id']}",$mysqli) )  {
-      $_SESSION['mailenvoi'] = $mailenvoi;
-      exit('{"etat":"ok","message":"Vos préférences d\'envoi de mail ont été modifiées."}');
-    }
+    // Éxécution
+    if ( requete('utilisateurs',"UPDATE utilisateurs SET mailexp = '$mailexp', mailcopie = ".intval(isset($_REQUEST['mailcopie']))." WHERE id = ${_SESSION['id']}",$mysqli) )
+      exit('{"etat":"ok","message":"Vos préférences d\'envoi de courriel ont été modifiées."}');
     exit('{"etat":"nok","message":"Votre compte n\'a pas été modifié. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 
@@ -476,7 +543,7 @@
     exit('{"etat":"nok","message":"Il n\'a pas d\'heure de colle à relever aujourd\'hui."}');
   if ( requete('heurescolles','UPDATE heurescolles SET releve=CURDATE() WHERE releve=0', $mysqli) )
     exit($_SESSION['message'] = '{"etat":"ok","message":"De nouvelles heures de colles ont été relevées et apparaissent dans le tableau général."}');
-  exit('{"etat":"nok","message":"L\'information n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+  exit('{"etat":"nok","message":"La relève n\'a pas été réalisée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
 }
 
 /////////////////////////////////////////////////
@@ -502,27 +569,30 @@
   $r = $resultat->fetch_assoc();
   $resultat->free();
 
-  // Traitement d'une modification
-  if ( isset($_REQUEST['champ']) && in_array($champ = $_REQUEST['champ'],array('titre','texte')) )  {
+  // Traitement d'une modification : titre, texte, protection
+  if ( isset($_REQUEST['champ']) )  {
     $valeur = trim($mysqli->real_escape_string($_REQUEST['val']));
-    if ( ( $champ == 'texte' ) && ( !strlen($valeur) ) )
-      exit('{"etat":"nok","message":"L\'information n\'a pas été modifiée. Le texte doit être non vide."}');
-    elseif ( requete('infos',"UPDATE infos SET $champ = '$valeur' WHERE id = $id",$mysqli) )  {
-      recent($mysqli,1,$id,$r['mat'],( $champ == 'titre' ) ? array('titre'=>( $valeur ?: 'Information')) : array('texte'=>$valeur));
-      exit('{"etat":"ok","message":"L\'information a été modifiée."}');
-    }
-    exit('{"etat":"nok","message":"L\'information n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
-  }
-
-  // Changement de protection
-  if ( isset($_REQUEST['champ']) && ( $_REQUEST['champ'] == 'protection' ) && ctype_digit($valeur = $_REQUEST['val']) )  {
-    if ( $r['protection'] == $valeur )
-      exit('{"etat":"nok","message":"La protection de l\'information n\'a pas été modifiée car elle est inchangée."}');
-    if ( requete('infos',"UPDATE infos SET protection = $valeur WHERE id = $id",$mysqli) )  {
-      recent($mysqli,1,$id,$r['mat'],array('protection'=>$valeur));
-      exit('{"etat":"ok","message":"L\'information a été modifiée."}');
-    }
-    exit('{"etat":"nok","message":"L\'information n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+    $champ = $_REQUEST['champ'];
+    if ( isset($r[$champ = $_REQUEST['champ']]) && ( $r[$champ] == $valeur ) )
+      exit('{"etat":"nok","message":"L\'information n\'a pas été modifiée."}');
+    if ( $champ == 'titre' )
+      exit( requete('infos',"UPDATE infos SET titre = '$valeur' WHERE id = $id",$mysqli)
+         && recent($mysqli,1,$id,array('titre'=>$valeur),false)
+         ? '{"etat":"ok","message":"Le titre de l\'information a été modifié."}'
+         : '{"etat":"nok","message":"L\'information n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+    if ( $champ == 'texte' )  {
+      if ( !$valeur )
+        exit('{"etat":"nok","message":"L\'information n\'a pas été modifiée. Le texte doit être non vide."}');
+      exit( requete('infos',"UPDATE infos SET texte = '$valeur' WHERE id = $id",$mysqli)
+         && recent($mysqli,1,$id,array('texte'=>$valeur),isset($_REQUEST['publi']))
+         ? '{"etat":"ok","message":"Le texte de l\'information a été modifié."}'
+         : '{"etat":"nok","message":"L\'information n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+    }
+    if ( ( $champ == 'protection' ) && ctype_digit($valeur = $_REQUEST['val']) )
+      exit( requete('infos',"UPDATE infos SET protection = $valeur WHERE id = $id",$mysqli)
+         && recent($mysqli,1,$id,array('protection'=>$valeur),false)
+         ? '{"etat":"ok","message":"La protection de l\'information a été modifiée."}'
+         : '{"etat":"nok","message":"L\'information n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 
   // Déplacement vers le haut
@@ -538,32 +608,24 @@
       : '{"etat":"nok","message":"L\'information n\'a pas été déplacée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
 
   // Positionnement "montré" (apparaît sur la partie publique)
-  if ( isset($_REQUEST['montre']) )  {
-    if ( requete('infos',"UPDATE infos SET cache = 0 WHERE id = $id",$mysqli) )  {
-      recent($mysqli,1,$id,$r['mat'],array('titre'=>( strlen($r['titre']) ? $mysqli->real_escape_string($r['titre']) : 'Information'), 'lien'=>".?${r['cle']}", 'texte'=>$mysqli->real_escape_string($r['texte']), 'matiere'=>$r['mat'], 'protection'=>$r['protection']));
-      exit('{"etat":"ok","message":"L\'information apparaît désormais sur la partie publique."}');
-    }
-    exit('{"etat":"nok","message":"L\'information n\'a pas été diffusée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
-  }
+  if ( isset($_REQUEST['montre']) )
+    exit( requete('infos',"UPDATE infos SET cache = 0 WHERE id = $id",$mysqli) 
+       && recent($mysqli,1,$id,array('matiere'=>$r['mat'],'titre'=>( strlen($r['titre']) ? $mysqli->real_escape_string($r['titre']) : 'Information'), 'lien'=>".?${r['cle']}", 'texte'=>$mysqli->real_escape_string($r['texte']), 'protection'=>$r['protection']) )
+        ? '{"etat":"ok","message":"L\'information apparaît désormais sur la partie publique."}'
+        : '{"etat":"nok","message":"L\'information n\'a pas été diffusée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
 
   // Positionnement "caché" (n'apparaît pas sur la partie publique)
-  if ( isset($_REQUEST['cache']) )  {
-    if ( requete('infos',"UPDATE infos SET cache = 1 WHERE id = $id",$mysqli) )  {
-      recent($mysqli,1,$id,$r['mat']);
-      exit('{"etat":"ok","message":"L\'information n\'apparaît plus sur la partie publique mais est toujours disponible ici pour modification ou diffusion."}');
-    }
-    exit('{"etat":"nok","message":"L\'information n\'a pas été cachée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
-  }
+  if ( isset($_REQUEST['cache']) )
+    exit( requete('infos',"UPDATE infos SET cache = 1 WHERE id = $id",$mysqli) && recent($mysqli,1,$id) 
+        ? '{"etat":"ok","message":"L\'information n\'apparaît plus sur la partie publique mais est toujours disponible ici pour modification ou diffusion."}'
+        : '{"etat":"nok","message":"L\'information n\'a pas été cachée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
 
   // Suppression
-  if ( isset($_REQUEST['supprime']) )  {
-    if ( requete('infos',"DELETE FROM infos WHERE id = $id",$mysqli) 
-      && requete('infos',"UPDATE infos SET ordre = (ordre-1) WHERE ordre > ${r['ordre']} AND page = ${r['page']}",$mysqli) )  {
-      recent($mysqli,1,$id,$r['mat']);
-      exit('{"etat":"ok","message":"Suppression réalisée"}');
-    }
-    exit('{"etat":"nok","message":"L\'information n\'a pas été supprimée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
-  }
+  if ( isset($_REQUEST['supprime']) )
+    exit( requete('infos',"DELETE FROM infos WHERE id = $id",$mysqli) && recent($mysqli,1,$id)
+       && requete('infos',"UPDATE infos SET ordre = (ordre-1) WHERE ordre > ${r['ordre']} AND page = ${r['page']}",$mysqli)
+        ? '{"etat":"ok","message":"Suppression réalisée"}'
+        : '{"etat":"nok","message":"L\'information n\'a pas été supprimée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
 }
 
 /////////////////////////////
@@ -577,26 +639,30 @@
   $r = $resultat->fetch_assoc();
   $resultat->free();
   // Génération de la valeur de protection
+  // $val est un tableau contenant soit 0, soit 32, soit 6 puis les valeurs des types de comptes autorisés
   if ( !count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )
     exit('{"etat":"nok","message":"L\'information n\'a pas été ajoutée. La protection d\'accès est incorrecte."}');
-  if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-    $protection = $val[0];
-  else  {
-    $protection = 32;
-    foreach (array_slice($val,1) as $v) 
-      $protection = $protection-2**($v-1);
-  }
+  $protection = ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32);
   // Autres données
   $titre = trim($mysqli->real_escape_string($_REQUEST['titre']));
   $texte = trim($mysqli->real_escape_string($_REQUEST['texte']));
   $cache = intval(isset($_REQUEST['cache']));
-  if ( !strlen($texte) )
+  if ( !$texte )
     exit('{"etat":"nok","message":"L\'information n\'a pas été ajoutée. Le texte doit être non vide."}');
   // Écriture
   if ( requete('infos',"UPDATE infos SET ordre = (ordre+1) WHERE page = $page",$mysqli)
     && requete('infos',"INSERT INTO infos SET ordre = 1, page = $page, texte = '$texte', titre = '$titre', cache = $cache, protection = $protection",$mysqli) )  {
-    if ( !$cache )
-      recent($mysqli,1,$mysqli->insert_id,$r['mat'],array('titre'=>( $titre ?: 'Information'), 'lien'=>".?${r['cle']}", 'texte'=>$texte, 'matiere'=>$r['mat'], 'protection'=>$protection));
+    $id = $mysqli->insert_id;
+    if ( !$cache )  {
+      $titre = ( $titre ?: 'Information');
+      if ( $page > 1 )  {
+        $resultat = $mysqli->query("SELECT CONCAT( ' [', IF(mat=0,'',CONCAT(m.nom,'/')),p.nom,']')
+                                    FROM pages AS p LEFT JOIN matieres AS m ON mat=m.id WHERE p.id = $page");
+        $titre .= $mysqli->real_escape_string($resultat->fetch_row()[0]);
+        $resultat->free();
+      }
+      recent($mysqli,1,$id,array('matiere'=>$r['mat'], 'titre'=>$titre, 'lien'=>".?${r['cle']}", 'texte'=>$texte, 'protection'=>$protection));
+    }
     $mysqli->query('ALTER TABLE infos ORDER BY page,ordre');
     exit($_SESSION['message'] = '{"etat":"ok","message":"L\'information a été ajoutée."}');
   }
@@ -619,98 +685,98 @@
   if ( isset($_REQUEST['champ']) && ( $_REQUEST['champ'] == 'nom' ) )  {
     if ( !$r['parent'] )
       exit('{"etat":"nok","message":"Le nom des répertoires racine des matières ne sont pas modifiables."}');
-    if ( !strlen($valeur = trim($mysqli->real_escape_string($_REQUEST['val'])) ) )
+    if ( !($valeur = trim($mysqli->real_escape_string($_REQUEST['val'])) ) )
       exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été modifié. Le nom doit être non vide.\"}");
-    if ( !requete('reps',"UPDATE reps SET nom = '$valeur' WHERE id = $id",$mysqli) )
-      exit("{\"etat\":\"nok\",\"message\":\"Le nom du répertoire <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
-    exit("{\"etat\":\"ok\",\"message\":\"Le nom du répertoire <em>${r['nom']}</em> a été modifié.}");
+    exit( requete('reps',"UPDATE reps SET nom = '$valeur' WHERE id = $id",$mysqli)
+       && requete('recents',"UPDATE recents SET texte = ( SELECT CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' ))
+                                                          FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) WHERE d.id = recents.id GROUP BY d.id )
+                                            WHERE type = 3 AND id IN (SELECT docs.id FROM docs WHERE FIND_IN_SET($id,parents))",$mysqli)
+       && rss($mysqli,$r['matiere'],0)
+        ? "{\"etat\":\"ok\",\"message\":\"Le nom du répertoire <em>${r['nom']}</em> a été modifié.}"
+        : "{\"etat\":\"nok\",\"message\":\"Le nom du répertoire <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
     
   // Traitement d'une modification globale
   if ( isset($_REQUEST['protection']) )  {
-    $requete = $message = array();
-    $etat = 'ok';
-    // Modification du nom, de l'affichage dans le menu uniquement si pas à la racine
+    $etat = 'nok';
+    // Modification du nom et de l'affichage dans le menu uniquement si pas à la racine
     if ( $r['parent'] && isset($_REQUEST['nom']) )  {
-      if ( strlen( $nom = trim($mysqli->real_escape_string($_REQUEST['nom'])) ) && ( $nom != $r['nom'] ) )
-        $requete[] = "nom = '$nom'";
-      $menu = intval(isset($_REQUEST['menu']));
-      if ( $menu != $r['menu'] )
-        $requete[] = "menu = $menu";
+      if ( ( $nom = trim($mysqli->real_escape_string($_REQUEST['nom'])) ) && ( $nom != $r['nom'] ) )  {
+        if ( !requete('reps', "UPDATE reps SET nom = '$nom' WHERE id = $id",$mysqli)
+          || !requete('recents',"UPDATE recents SET texte = ( SELECT CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' ))
+                                                              FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) WHERE d.id = recents.id GROUP BY d.id )
+                                                WHERE type = 3 AND id IN (SELECT docs.id FROM docs WHERE FIND_IN_SET($id,parents))",$mysqli) )
+          exit("{\"etat\":\"nok\",\"message\":\"Le nom du répertoire <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+        rss($mysqli,$r['matiere'],0);
+        // Mise à jour de l'ordre des répertoires
+        $mysqli->query('ALTER TABLE reps ORDER BY parents,nom');
+        $etat = 'ok';
+      }
+      if ( ( $menu = intval(isset($_REQUEST['menu']))) != $r['menu'] )  {
+        requete('reps', "UPDATE reps SET menu = 1-menu WHERE id = $id",$mysqli);
+        $etat = 'ok';
+      }
     }
+    
     // Génération de la valeur de protection
-    if ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )  {
-      if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-        $protection = $val[0];
-      else  {
-        $protection = 32;
-        foreach (array_slice($val,1) as $v) 
-          $protection = $protection-2**($v-1);
-      }
-      if ( $protection != $r['protection'] )
-        $requete[] = "protection = $protection";
-    }
-    if ( $requete )  {
-      if ( requete('reps','UPDATE reps SET '.implode(', ',$requete)." WHERE id = $id",$mysqli) ) 
-        $message[] = "Le répertoire <em>${r['nom']}</em> a été modifié.";
-      else  {
-        $message[] = "Le répertoire <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-        $etat = 'nok';
-      }
+    // $val est un tableau contenant soit 0, soit 32, soit 6 puis les valeurs des types de comptes autorisés
+    // Pas de modification de la table recents ici : seule la protection du répertoire change
+    if ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); }))
+      && ( $r['protection'] != ( $protection = ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32) ) ) )  {
+      if ( !requete('reps', "UPDATE reps SET protection = $protection WHERE id = $id",$mysqli) )
+        exit("{\"etat\":\"nok\",\"message\":\"La protection du répertoire <em>${r['nom']}</em> n'a pas été modifiée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+      // Modification de la matière si protection du répertoire racine modifié
+      if ( !$r['parent'] && $r['matiere'] )
+        requete('matieres',"UPDATE matieres SET docs_protection = $protection WHERE id = ${r['matiere']}",$mysqli);
+      $etat = 'ok';
+      // Pour une éventuelle propagation
+      $r['protection'] = $protection;
     }
+
     // Déplacement du répertoire si $_REQUEST['parent'] non nul et si pas à la racine
-    if ( $r['parent'] && isset($_REQUEST['parent']) && !in_array($parent = intval($_REQUEST['parent']),array(0,$id,$r['parent'])) )  {
-      // Vérification du répertoire parent
+    if ( $r['parent'] && isset($_REQUEST['parent']) && ctype_digit($parent = $_REQUEST['parent']) && !in_array($parent,array(0,$id,$r['parent'])) )  {
+      // Vérification du nouveau répertoire parent
       $resultat = $mysqli->query("SELECT parents, matiere FROM reps WHERE id = $parent AND FIND_IN_SET(matiere,'${_SESSION['matieres']}') AND NOT FIND_IN_SET($id,parents)");
-      if ( $resultat->num_rows)  {
-        $s = $resultat->fetch_assoc();
-        $resultat->free();
-        $mat = $s['matiere'];
-        $parents = "${s['parents']},$parent";
-        if ( requete('reps',"UPDATE reps SET matiere = $mat, parent = $parent, parents = '$parents' WHERE id = $id",$mysqli)
-          && requete('reps',"UPDATE reps SET matiere = $mat, parents = '$parents,$id' WHERE parent = $id",$mysqli)
-          && requete('docs',"UPDATE docs SET matiere = $mat, parents = '$parents,$id' WHERE parent = $id",$mysqli)
-          && $mysqli->query('UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32)') )
-          $message[] = "Le répertoire <em>${r['nom']}</em> a été déplacé.";
-        else  {
-          $message[] = "Le répertoire <em>${r['nom']}</em> n'a pas été déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-          $etat = 'nok';
-        }
-      }
-      else  {
-        $message[] = "Le répertoire <em>${r['nom']}</em> n'a pas été déplacé. Identifiant de répertoire parent non valide.";
-        $etat = 'nok';
-      }
-    }
-    // Reconstruction du message
-    if ( $message )  {
-      // Mise à jour de l'ordre des répertoires
+      if ( !$resultat->num_rows)
+        exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été déplacé. Identifiant de répertoire parent non valide.\"}");
+      $s = $resultat->fetch_assoc();
+      $resultat->free();
+      $mat = $s['matiere'];
+      $parents = "${s['parents']},$parent";
+      if ( !requete('reps',"UPDATE reps SET matiere = $mat, parent = $parent, parents = '$parents' WHERE id = $id",$mysqli)
+        || !requete('reps',"UPDATE reps SET matiere = $mat, parents = '$parents,$id' WHERE parent = $id",$mysqli)
+        || !requete('docs',"UPDATE docs SET matiere = $mat, parents = '$parents,$id' WHERE parent = $id",$mysqli)
+        || !requete('recents',"UPDATE recents SET matiere = $mat,
+                                                  texte = ( SELECT CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' ))
+                                                            FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) WHERE d.id = recents.id GROUP BY d.id )
+                                              WHERE type = 3 AND id IN (SELECT docs.id FROM docs WHERE FIND_IN_SET($id,parents))",$mysqli)
+        || !rss($mysqli, ( $r['matiere'] != $mat ) ? array($r['matiere'],$mat) : $mat, 0) )
+        exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+      // Mise à jour du menu et de l'ordre des répertoires
+      $mysqli->query("UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32) WHERE id = ${r['matiere']} OR id = $mat");
       $mysqli->query('ALTER TABLE reps ORDER BY parents,nom');
-      if ( $etat == 'nok')
-        exit('{"etat":"nok","message":"'.implode(', ',$message).'"}');
-      // Modification de la matière si protection du répertoire racine modifié
-      if ( !$r['parent'] && $r['matiere'] && $protection != $r['protection'] )
-        requete('matieres',"UPDATE matieres SET docs_protection = $protection WHERE id = ${r['matiere']}",$mysqli);
-      exit($_SESSION['message'] = '{"etat":"ok","message":"'.implode(', ',$message).'"}');
+      $etat = 'ok';
     }
-    exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été modifié. Aucune modification demandée.\"}");
+    
+    // Propagation des droits d'accès aux sous-répertoires et documents
+    if ( isset($_REQUEST['propage']) )  {
+      if ( requete('reps',"UPDATE reps SET protection = ${r['protection']} WHERE FIND_IN_SET($id,parents)",$mysqli)
+        && requete('docs',"UPDATE docs SET protection = ${r['protection']} WHERE FIND_IN_SET($id,parents)",$mysqli)
+        && requete('recents',"UPDATE recents SET protection = ${r['protection']} WHERE type = 3 AND id IN (SELECT docs.id FROM docs WHERE FIND_IN_SET($id,parents))",$mysqli)
+        && rss($mysqli,$r['matiere'],0) )  {
+        // Mise à jour de la matière (menu)
+        $mysqli->query("UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = ${r['matiere']} AND protection < 32) WHERE id = ${r['matiere']}");
+        exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le réglage d'accès du répertoire <em>${r['nom']}</em> a été propagé à tous les documents et sous-répertoires qu'il contient.\"}");
+      }
+      exit("{\"etat\":\"nok\",\"message\":\"Le réglage d'accès du répertoire <em>${r['nom']}</em> n'a pas été propagé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    }
+  
+    // Si pas de modification
+    if ( $etat == 'nok' )
+      exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été modifié. Aucune modification demandée.\"}");
+    exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le répertoire <em>${r['nom']}</em> a été modifié.\"}");
   }
   
-  // Propagation des droits d'accès aux sous-répertoires et documents
-  // Les infos récentes sont modifiées dans la base, mais les flux RSS
-  // ne seront affectés qu'à la prochaine exécution de recents() et donc rss()
-  if ( isset($_REQUEST['propage']) )  {
-    if ( requete('reps',"UPDATE reps SET protection = ${r['protection']} WHERE FIND_IN_SET($id,parents)",$mysqli) && requete('docs',"UPDATE docs SET protection = ${r['protection']} WHERE FIND_IN_SET($id,parents)",$mysqli) )  {
-      // Mise à jour des informations récentes
-      requete('recents',"UPDATE recents SET protection = ${r['protection']} WHERE id IN (SELECT 3000+docs.id FROM docs WHERE FIND_IN_SET($id,parents))",$mysqli);
-      rss($mysqli, ( $r['matiere'] == 0 ) ? array(0) : array(0,$r['matiere']) );
-      // Mise à jour de la matière (menu)
-      $mysqli->query('UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32)');
-      exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le réglage d'accès du répertoire <em>${r['nom']}</em> a été propagé à tous les documents et sous-répertoires qu'il contient.\"}");
-    }
-    exit("{\"etat\":\"nok\",\"message\":\"Le réglage d'accès du répertoire <em>${r['nom']}</em> n'a pas été propagé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
-  }
-
   // Suppression du répertoire ou de son contenu
   if ( isset($_REQUEST['supprime']) || isset($_REQUEST['vide']) )  {
     if ( isset($_REQUEST['supprime']) )  {
@@ -724,22 +790,24 @@
       $requete = '';
     }
     if ( requete('reps',"DELETE FROM reps WHERE $requete FIND_IN_SET($id,parents)",$mysqli) )  {
-      // Suppression physique
+      // Suppression physique des documents
       $resultat = $mysqli->query("SELECT lien FROM docs WHERE FIND_IN_SET($id,parents)");
       if ( $resultat->num_rows )  {
         while ( $s = $resultat->fetch_row() )
           exec("rm -rf documents/${s[0]}");
         $resultat->free();
-        if ( !requete('docs',"DELETE FROM docs WHERE FIND_IN_SET($id,parents)",$mysqli) )
+        if ( !requete('recents',"DELETE FROM recents WHERE type = 3 AND id IN (SELECT docs.id FROM docs WHERE FIND_IN_SET($id,parents))",$mysqli)
+          || !requete('docs',"DELETE FROM docs WHERE FIND_IN_SET($id,parents)",$mysqli)
+          || !rss($mysqli,$r['matiere'],0) )
           exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été correctement $action. Certains documents sont encore dans la base de données. Vous devriez en informer l'administrateur. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
       }
-      $mysqli->query('UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32)');
+      // Mise à jour de la matière (menu)
+      $mysqli->query("UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = ${r['matiere']} AND protection < 32) WHERE id = ${r['matiere']}");
       if ( $action == 'vidé' )
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le répertoire <em>${r['nom']}</em> a été vidé de son contenu, ainsi que tous ses sous-répertoires.\"}");
       exit("{\"etat\":\"ok\",\"message\":\"Le répertoire <em>${r['nom']}</em> a été supprimé, ainsi que tous ses sous-répertoires et ses documents.\"}");
     }
-    else
-      exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été $action. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    exit("{\"etat\":\"nok\",\"message\":\"Le répertoire <em>${r['nom']}</em> n'a pas été $action. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 }
 
@@ -755,20 +823,12 @@
   $resultat->free();
   $menu = intval(isset($_REQUEST['menu']));
   // Génération de la valeur de protection
-  if ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )  {
-    if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-      $protection = $val[0];
-    else  {
-      $protection = 32;
-      foreach (array_slice($val,1) as $v) 
-        $protection = $protection-2**($v-1);
-    }
-  }
-  else
-    $protection = $r['protection'];
+  $protection = ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )
+                ? ( ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32) )
+                : $r['protection'];
   if ( !requete('reps',"INSERT INTO reps SET parent = $parent, parents = '${r['parents']},$parent', nom = '$nom', matiere = ${r['matiere']}, protection = $protection, menu = $menu",$mysqli) )
     exit('{"etat":"nok","message":"Le répertoire n\'a pas été ajouté. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
-  // Mise à jour
+  // Mise à jour de l'ordre des répertoires
   $mysqli->query('ALTER TABLE reps ORDER BY parents,nom');
   exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le répertoire <em>$nom</em> a été ajouté.\"}");
 }
@@ -786,152 +846,106 @@
 
   // Traitement d'une modification unique (nom)
   if ( isset($_REQUEST['champ']) && ( $_REQUEST['champ'] == 'nom' ) )  {
-    if ( !strlen( $valeur = trim($_REQUEST['val']) ) )
+    if ( !( $valeur = trim($_REQUEST['val']) ) )
       exit("{\"etat\":\"nok\",\"message\":\"Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Le nom doit être non vide.\"}");
-    if ( $valeur != $r['nom'] )  {
-      setlocale(LC_CTYPE, "fr_FR.UTF-8");
-      $nom = substr((str_replace(array($r['ext'],'\\','/'),array('','-','-'),$valeur)),0,100);
-      // real_escape_string seulement pour la requête SQL
-      $nouveau_nom = $mysqli->real_escape_string($nom);
-      if ( !requete('docs',"UPDATE docs SET nom = '$nouveau_nom', nom_nat = '".zpad($nouveau_nom)."' WHERE id = $id",$mysqli) )
-        exit("{\"etat\":\"nok\",\"message\":\"Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
-      exec('mv documents/'.escapeshellarg("${r['lien']}/${r['nom']}${r['ext']}").' documents/'.escapeshellarg("${r['lien']}/$nom${r['ext']}"));
-      $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
-      // Modification de l'éventuelle information récente
-      if ( $r['protection'] < 32 )
-        recent($mysqli,3,$id,$r['matiere'],array('nom'=>$nouveau_nom,'ancien_nom'=>$r['nom']));
-      exit("{\"etat\":\"ok\",\"message\":\"Le nom du document <em>${r['nom']}</em> a été modifié.\"}");
-    }
-    exit("{\"etat\":\"nok\",\"message\":\"Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Aucune modification demandée.\"}");
+    if ( $valeur == $r['nom'] ) 
+      exit("{\"etat\":\"nok\",\"message\":\"Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Aucune modification demandée.\"}");
+    setlocale(LC_CTYPE, "fr_FR.UTF-8");
+    $nom = substr((str_replace(array($r['ext'],'\\','/'),array('','-','-'),$valeur)),0,100);
+    // real_escape_string seulement pour la requête SQL
+    $nouveau_nom = $mysqli->real_escape_string($nom);
+    if ( !requete('docs',"UPDATE docs SET nom = '$nouveau_nom', nom_nat = '".zpad($nouveau_nom)."' WHERE id = $id",$mysqli) )
+      exit("{\"etat\":\"nok\",\"message\":\"Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    exec('mv documents/'.escapeshellarg("${r['lien']}/${r['nom']}${r['ext']}").' documents/'.escapeshellarg("${r['lien']}/$nom${r['ext']}"));
+    $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
+    recent($mysqli,3,$id,array('titre'=>$nouveau_nom),false);
+    exit("{\"etat\":\"ok\",\"message\":\"Le nom du document <em>${r['nom']}</em> a été modifié.\"}");
   }
 
   // Traitement d'une modification globale
-  if ( isset($_REQUEST['nom']) && isset($_REQUEST['parent']) && isset($_REQUEST['protection']) && strlen($nom = trim($_REQUEST['nom'])) )  {
-    $requete = $message = array();
-    $etat = 'ok';
+  if ( isset($_REQUEST['nom']) && isset($_REQUEST['parent']) && isset($_REQUEST['protection']) && ($nom = trim($_REQUEST['nom'])) )  {
+    $etat = 'nok';
+    $message = '';
+    
     // Modification du nom
     setlocale(LC_CTYPE, "fr_FR.UTF-8");
     $nom = substr(basename(str_replace(array($r['ext'],'\\'),array('','/'),$nom)),0,100);
     if ( $nom != $r['nom'] )  {
       // real_escape_string seulement pour la requête SQL
       $nouveau_nom = $mysqli->real_escape_string($nom);
-      if ( requete('docs',"UPDATE docs SET nom = '$nouveau_nom', nom_nat = '".zpad($nouveau_nom)."' WHERE id = $id",$mysqli) )  {
-        exec('mv documents/'.escapeshellarg("${r['lien']}/${r['nom']}${r['ext']}").' documents/'.escapeshellarg("${r['lien']}/$nom${r['ext']}"));
-        $message[] = "Le nom du document <em>${r['nom']}</em> a été modifié.";
-        // Modification de l'éventuelle information récente
-        if ( $r['protection'] < 32 )
-          recent($mysqli,3,$id,$r['matiere'],array('nom'=>$nouveau_nom,'ancien_nom'=>$r['nom']));
-      }
-      else  {
-        $message[] = "Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-        $etat = 'nok';
-      }
+      if ( !requete('docs',"UPDATE docs SET nom = '$nouveau_nom', nom_nat = '".zpad($nouveau_nom)."' WHERE id = $id",$mysqli) )
+        exit("{\"etat\":\"nok\",\"message\":\"Le nom du document <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+      exec('mv documents/'.escapeshellarg("${r['lien']}/${r['nom']}${r['ext']}").' documents/'.escapeshellarg("${r['lien']}/$nom${r['ext']}"));
+      $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
+      recent($mysqli,3,$id,array('titre'=>$nouveau_nom),false);
+      $etat = 'ok';
+      $message = "Le nom du document <em>${r['nom']}</em> a été modifié.<br>";
+      // Modification du nom (nécessaire pour les éventuels affichages suivants et la mise à jour éventuelle du fichier)
+      $r['nom'] = $nom;
     }
+    
     // Modification de la protection
     if ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )  {
-      if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-        $protection = $val[0];
-      else  {
-        $protection = 32;
-        foreach (array_slice($val,1) as $v) 
-          $protection = $protection-2**($v-1);
-      }
-      if ( $protection != $r['protection'] )  {
-        if ( requete('docs',"UPDATE docs SET protection = $protection WHERE id = $id",$mysqli) )  {
-          $message[] = "L'accès au document <em>${r['nom']}</em> a été modifié.";
-          // Si $protection = 32, on cherche à supprimer l'info récente
-          if ( $protection == 32 )
-            recent($mysqli,3,$id,$r['matiere']);
-          // Si doc avant protégé, on crée une info récente de nouveau doc
-          elseif ( $r['protection'] == 32 )  {
-            $resultat = $mysqli->query("SELECT GROUP_CONCAT( reps.nom ORDER BY FIND_IN_SET(reps.id,docs.parents) SEPARATOR '/' ) AS path, docs.nom
-                                        FROM docs LEFT JOIN reps ON FIND_IN_SET(reps.id,docs.parents) WHERE docs.id = $id");
-            $s = $resultat->fetch_assoc();
-            $resultat->free();
-            $path = $mysqli->real_escape_string("${s['path']}/${s['nom']}");
-            recent($mysqli,3,$id,$r['matiere'],array('titre'=>$path, 'lien'=>"download?id=$id", 'texte'=>"<p>Nouveau document&nbsp;: <a href=\"download?id=$id\">$path</a></p>", 'matiere'=>$r['matiere'], 'protection'=>$protection),$r['ext']);
-          }
-          // Sinon, mise à jour de la protection dans les informations récentes
-          else
-            recent($mysqli,3,$id,$r['matiere'],array('protection'=>$protection));
-        }
-        else  {
-          $message[] = "L'accès au document <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-          $etat = 'nok';
-          $protection = $r['protection'];
-        }
+      if ( $r['protection'] != ( $protection = ( ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32) ) ) )  {
+        if ( !requete('docs',"UPDATE docs SET protection = $protection WHERE id = $id",$mysqli)
+          || !recent($mysqli,3,$id,array('protection'=>$protection),false) )
+          exit("{\"etat\":\"nok\",\"message\":\"$message L'accès au document <em>${r['nom']}</em> n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+        // Mise à jour du menu
+        $mysqli->query("UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = ${r['matiere']} AND protection < 32) WHERE id = ${r['matiere']}");
+        $etat = 'ok';
+        $message .= "L'accès au document <em>${r['nom']}</em> a été modifié.<br>";
+        // Modification de la protection (nécessaire pour les éventuels prochains appel à rss())
+        $r['protection'] = $protection;
       }
     }
 
     // Déplacement dans un autre répertoire
     if ( ctype_digit($parent = $_REQUEST['parent']) && $parent && ( $parent != $r['parent'] ) )  {
-      // Vérification du répertoire parent
+      // Vérification du nouveau répertoire parent
       $resultat = $mysqli->query("SELECT parents, matiere FROM reps WHERE id = $parent AND FIND_IN_SET(matiere,'${_SESSION['matieres']}')");
-      if ( $resultat->num_rows )  {
-        $s = $resultat->fetch_assoc();
-        $resultat->free();
-        if ( requete('docs',"UPDATE docs SET parent = '$parent', parents = '${s['parents']},$parent', matiere = ${s['matiere']} WHERE id = $id",$mysqli) )  {
-          $message[] = "Le document <em>${r['nom']}</em> a été déplacé.";
-          // Modification de l'information récente si document visible
-          if ( $protection < 32 )  {
-            $resultat = $mysqli->query("SELECT GROUP_CONCAT( reps.nom ORDER BY FIND_IN_SET(reps.id,docs.parents) SEPARATOR '/' ) AS path, docs.nom, docs.matiere
-                                        FROM docs LEFT JOIN reps ON FIND_IN_SET(reps.id,docs.parents) WHERE docs.id = $id");
-            $s = $resultat->fetch_assoc();
-            $resultat->free();
-            recent($mysqli,3,$id,$r['matiere'],array('chemin'=>$mysqli->real_escape_string("${s['path']}/${s['nom']}"), 'matiere'=>$s['matiere']));
-          }
-        }
-        else  {
-          $message[] = "Le document <em>${r['nom']}</em> n'a pas été déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-          $etat = 'nok';
-        }
-      }
-      else  {
-        $message[] = "Le document <em>${r['nom']}</em> n'a pas été déplacé. Identifiant de répertoire parent non valide.";
-        $etat = 'nok';
-      }
+      if ( !$resultat->num_rows )
+        exit("{\"etat\":\"nok\",\"message\":\"$message Le document <em>${r['nom']}</em> n'a pas été déplacé. Identifiant de répertoire parent non valide.\"}");
+      $s = $resultat->fetch_assoc();
+      $resultat->free();
+      $mat = $s['matiere'];
+      if ( !requete('docs',"UPDATE docs SET parent = '$parent', parents = '${s['parents']},$parent', matiere = $mat WHERE id = $id",$mysqli) 
+        || !requete('recents',"UPDATE recents SET matiere = $mat,
+                                                  texte = ( SELECT CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' ))
+                                                            FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) WHERE d.id = $id )
+                                              WHERE type = 3 AND id = $id",$mysqli)
+        || !rss($mysqli, ( $r['matiere'] != $mat ) ? array($r['matiere'],$mat) : $mat, $r['protection']) )
+        exit("{\"etat\":\"nok\",\"message\":\"$message Le document <em>${r['nom']}</em> n'a pas été déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+      // Mise à jour du menu et de l'ordre des documents
+      $mysqli->query("UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32) WHERE id = ${r['matiere']} OR id = $mat");
+      $mysqli->query('ALTER TABLE reps ORDER BY parents,nom');
+      $etat = 'ok';
+      $message .= "Le document <em>${r['nom']}</em> a été déplacé.<br>";
+      // Modification de la matière (nécessaire pour les éventuels prochains appel à rss())
+      $r['matiere'] = $mat;
     }
+    
     // Mise à jour d'un document
     if ( isset($_FILES['fichier']['tmp_name']) && is_uploaded_file($_FILES['fichier']['tmp_name']) )  {
       // Changement d'extension interdit
-      $ext = ( strpos($_FILES['fichier']['name'],'.') ) ? strrchr($_FILES['fichier']['name'],'.') : '';
-      if ( $ext != $r['ext'] )  {
-        $message[] = "Le document <em>${r['nom']}</em> n'a pas été mis à jour. Le fichier envoyé est d'une extension différente.";
-        $etat = 'nok';
-      }
+      if ( $r['ext'] != ( $ext = ( strrchr($_FILES['fichier']['name'],'.') ?: '' ) ) )
+        exit("{\"etat\":\"nok\",\"message\":\"$message Le document <em>${r['nom']}</em> n'a pas été mis à jour. Le fichier envoyé est d'une extension différente.\"}");
+      // Gestion de la taille
+      $taille = ( ( $taille = intval($_FILES['fichier']['size']/1024) ) < 1024 ) ? "$taille&nbsp;ko" : intval($taille/1024).'&nbsp;Mo';
       // Déplacement du document uploadé au bon endroit
-      elseif ( move_uploaded_file($_FILES['fichier']['tmp_name'],"documents/${r['lien']}/${r['nom']}${r['ext']}") )  {
-        // Gestion de la taille
-        $taille = intval($_FILES['fichier']['size']/1024);
-        $taille = ( $taille < 1024 ) ? "$taille&nbsp;ko" : intval($taille/1024).'&nbsp;Mo';
-        // Modifications dans la base de données
-        requete('docs',"UPDATE docs SET upload = CURDATE(), taille = '$taille' WHERE id = $id",$mysqli);
-        // Info récente si document visible (éventuellement nouvelle)
-        if ( $protection < 32 )  {
-          // Besoin du chemin si pas d'info récente liée au document
-          $resultat = $mysqli->query("SELECT GROUP_CONCAT( reps.nom ORDER BY FIND_IN_SET(reps.id,docs.parents) SEPARATOR '/' ) AS path, docs.nom
-                                      FROM docs LEFT JOIN reps ON FIND_IN_SET(reps.id,docs.parents) WHERE docs.id = $id");
-          $s = $resultat->fetch_assoc();
-          $resultat->free();
-          recent($mysqli,3,$id,$r['matiere'],array('maj'=>$mysqli->real_escape_string("${s['path']}/${s['nom']}")));
-        }
-        $message[] = "Le document <em>${r['nom']}</em> a été mis à jour.";
-      }
-      else  {
-        $message[] = "Le document <em>$nom</em> n'a pas été mis à jour : problème d'écriture du fichier. Vous devriez en informer l'administrateur.";
-        $etat = 'nok';
-      }
-    }
-    // Reconstruction du message
-    if ( $message )  {
-      // Mise à jour de l'ordre des répertoires et de l'affichage des matières
-      $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
-      $mysqli->query('UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32)');
-      if ( $etat == 'nok')
-        exit('{"etat":"nok","message":"'.implode(', ',$message).'"}');
-      exit($_SESSION['message'] = '{"etat":"ok","message":"'.implode(', ',$message).'"}');
+      if ( !move_uploaded_file($_FILES['fichier']['tmp_name'],"documents/${r['lien']}/${r['nom']}${r['ext']}") )
+        exit("{\"etat\":\"nok\",\"message\":\"$message Le document <em>${r['nom']}</em> n'a pas été mis à jour : problème d'écriture du fichier. Vous devriez en informer l'administrateur.\"}");
+      // Modifications dans la base de données
+      if ( requete('docs','UPDATE docs SET '.( isset($_REQUEST['publi']) ? 'upload = CURDATE(), ' : '' )."taille = '$taille' WHERE id = $id",$mysqli)
+        && requete('recents','UPDATE recents SET '.( isset($_REQUEST['publi']) ? 'maj = NOW(), ' : '' )."texte = CONCAT(SUBSTRING_INDEX(texte,'|',1),'|$taille|',SUBSTRING_INDEX(texte,'|',-2))
+                              WHERE type = 3 AND id = $id",$mysqli)
+        && rss($mysqli,$r['matiere'],$r['protection']) )
+        exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"$message Le document <em>${r['nom']}</em> a été mis à jour.\"}");
     }
-    exit("{\"etat\":\"nok\",\"message\":\"Le document <em>${r['nom']}</em> n'a pas été modifié. Aucune modification demandée.\"}");
+    
+    // Message
+    if ( $etat == 'nok' )
+      exit("{\"etat\":\"nok\",\"message\":\"Le document <em>${r['nom']}</em> n'a pas été modifié. Aucune modification demandée.\"}");
+    exit($_SESSION['message'] = '{"etat":"ok","message":"'.substr($message,0,-4).'"}');
   }
   
   // Suppression d'un document
@@ -940,8 +954,8 @@
       exit("{\"etat\":\"nok\",\"message\":\"Le document <em>${r['nom']}</em> n'a pas été supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».');
     // Suppression physique
     exec("rm -rf documents/${r['lien']}");
-    recent($mysqli,3,$id,$r['matiere']);
-    $mysqli->query('UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = matieres.id AND protection < 32)');
+    recent($mysqli,3,$id);
+    $mysqli->query("UPDATE matieres SET docs = (SELECT IF(COUNT(*),1,0) FROM docs WHERE matiere = ${r['matiere']} AND protection < 32) WHERE id = ${r['matiere']}");
     exit("{\"etat\":\"ok\",\"message\":\"Le document <em>${r['nom']}</em> a été supprimé.\"}");
   }
 }
@@ -963,52 +977,39 @@
   setlocale(LC_CTYPE, "fr_FR.UTF-8");
   $nom = trim(substr(basename(str_replace(array($ext,'\\'),array('','/'), $_REQUEST['nom'] ?: $nom )),0,100));
   // Génération de la valeur de protection
-  if ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )  {
-    if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-      $protection = $val[0];
-    else  {
-      $protection = 32;
-      foreach (array_slice($val,1) as $v) 
-        $protection = $protection-2**($v-1);
-    }
-  }
-  else
-    $protection = $r['protection'];
+  $protection = ( count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )
+                ? ( ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32) )
+                : $r['protection'];
   // Création du répertoire particulier
   $lien = substr(sha1(mt_rand()),0,15);
   while ( is_dir("documents/$lien") )
     $lien = substr(sha1(mt_rand()),0,15);
   mkdir("documents/$lien");
   // Gestion de la taille
-  $taille = intval($_FILES['fichier']['size']/1024);
-  $taille = ( $taille < 1024 ) ? "$taille&nbsp;ko" : intval($taille/1024).'&nbsp;Mo';
+  $taille = ( ( $taille = intval($_FILES['fichier']['size']/1024) ) < 1024 ) ? "$taille&nbsp;ko" : intval($taille/1024).'&nbsp;Mo';
   // Déplacement du document uploadé au bon endroit
   if ( !move_uploaded_file($_FILES['fichier']['tmp_name'],"documents/$lien/$nom$ext") )
     exit("{\"etat\":\"nok\",\"message\":\"Le document <em>$nom</em> n'a pas été ajouté : problème d'écriture du fichier. Vous devriez en informer l'administrateur.\"}");
+
   // Écriture MySQL
+  // On doit garder $nom pour l'affichage
+  $nom_sql = $mysqli->real_escape_string($nom);
   if ( requete('docs',"INSERT INTO docs SET parent = $parent, parents = '${r['parents']},$parent',
-                       matiere = ${r['matiere']}, nom = '".$mysqli->real_escape_string($nom).'\', nom_nat = \''.zpad($mysqli->real_escape_string($nom))."', upload = CURDATE(),
+                       matiere = ${r['matiere']}, nom = '$nom_sql', nom_nat = '".zpad($nom_sql)."', upload = CURDATE(),
                        taille = '$taille', lien = '$lien', ext='".$mysqli->real_escape_string($ext)."', protection = $protection",$mysqli) )  {
     $id = $mysqli->insert_id;
-    // Mise à jour des informations récentes
-    if ( $protection < 32 )  {
-      $resultat = $mysqli->query("SELECT GROUP_CONCAT( reps.nom ORDER BY FIND_IN_SET(reps.id,docs.parents) SEPARATOR '/' ) AS path
-                                  FROM docs LEFT JOIN reps ON FIND_IN_SET(reps.id,docs.parents) WHERE docs.id = $id");
-      $s = $resultat->fetch_assoc();
-      $resultat->free();
-      $path = $mysqli->real_escape_string("${s['path']}/$nom");
-      recent($mysqli,3,$id,$r['matiere'],array('titre'=>$path, 'lien'=>"download?id=$id", 'texte'=>"<p>Nouveau document&nbsp;: <a href=\"download?id=$id\">$path</a></p>", 'matiere'=>$r['matiere'], 'protection'=>$protection),$ext);
-      // Mise à jour de l'affichage de la matière dans le menu)
-      $mysqli->query("UPDATE matieres SET docs = 1 WHERE id = ${r['matiere']}");
-    }
+    $resultat = $mysqli->query("SELECT GROUP_CONCAT(nom ORDER BY FIND_IN_SET(id,'${r['parents']},$parent') SEPARATOR '/' )
+                                FROM reps WHERE FIND_IN_SET(id,'${r['parents']},$parent')");
+    recent($mysqli,3,$id,array('matiere'=>$r['matiere'], 'titre'=>$nom_sql, 'lien'=>".?${r['cle']}", 'texte'=>$mysqli->real_escape_string("$ext|$taille|$parent|".$resultat->fetch_row()[0]), 'protection'=>$protection));
+    $resultat->free();
+    // Mise à jour de l'affichage de la matière dans le menu et de l'ordre des documents
+    $mysqli->query("UPDATE matieres SET docs = 1 WHERE id = ${r['matiere']}");
     $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
     exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le document <em>$nom</em> a été ajouté.\"}");
   }
-  else  {
-    // Retour en arrière
-    exec("rm -rf documents/$lien");
-    exit("{\"etat\":\"nok\",\"message\":\"Le document <em>$nom</em> n'a pas été ajouté. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
-  }
+  // Retour en arrière
+  exec("rm -rf documents/$lien");
+  exit("{\"etat\":\"nok\",\"message\":\"Le document <em>$nom</em> n'a pas été ajouté. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
 }
 
 ///////////////////////////////////////////
@@ -1029,49 +1030,44 @@
 
   // Traitement d'une modification unique (texte)
   if ( isset($_REQUEST['champ']) && ( $_REQUEST['champ'] == 'texte' ) )  {
-    $valeur = $mysqli->real_escape_string($_REQUEST['val']);
-    if ( !strlen($valeur) )
+    if ( !( $valeur = $mysqli->real_escape_string($_REQUEST['val']) ) )
       exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été modifié. Le texte doit être non vide.\"}");
-    if ( requete('colles',"UPDATE colles SET texte = '$valeur' WHERE id = ${r['id']}",$mysqli) )  {
-      if ( !$r['cache'] )
-        recent($mysqli,2,$r['id'],$mid,array('texte'=>$valeur));
-      exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} a été modifié.\"}");
-    }
-    exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    if ( !requete('colles',"UPDATE colles SET texte = '$valeur' WHERE id = ${r['id']}",$mysqli) )
+      exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été modifié. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    if ( !$r['cache'] )
+      recent($mysqli,2,$r['id'],array('texte'=>$valeur),isset($_REQUEST['publi']));
+    exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} a été modifié.\"}");
   }
 
   // Positionnement "montré" (apparaît sur la partie publique)
   if ( isset($_REQUEST['montre']) )  {
-    if ( requete('colles',"UPDATE colles SET cache = 0 WHERE id = ${r['id']}",$mysqli) )  {
-      // Fabrication des données pour les informations récentes
-      $resultat = $mysqli->query("SELECT nom, cle, colles_protection FROM matieres WHERE id = $mid");
-      $s = $resultat->fetch_assoc();
-      $resultat->free();
-      recent($mysqli,2,$r['id'],$mid,array('titre'=>"Colles du ${r['debut']} en ".$mysqli->real_escape_string($s['nom']), 'lien'=>"colles?${s['cle']}&amp;n=$sid", 'texte'=>$mysqli->real_escape_string($r['texte']), 'matiere'=>$mid, 'protection'=>$s['colles_protection']));
-      $mysqli->query($requete_maj);
-      exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} apparaît désormais sur la partie publique.\"}");
-    }
-    exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été diffusé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    if ( !requete('colles',"UPDATE colles SET cache = 0 WHERE id = ${r['id']}",$mysqli) )
+      exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été diffusé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    // Fabrication des données pour les informations récentes
+    $resultat = $mysqli->query("SELECT nom, cle, colles_protection FROM matieres WHERE id = $mid");
+    $s = $resultat->fetch_assoc();
+    $resultat->free();
+    recent($mysqli,2,$r['id'],array('matiere'=>$mid, 'titre'=>"Colles du ${r['debut']} en ".$mysqli->real_escape_string($s['nom']), 'lien'=>"colles?${s['cle']}&amp;n=$sid", 'texte'=>$mysqli->real_escape_string($r['texte']), 'protection'=>$s['colles_protection']));
+    $mysqli->query($requete_maj);
+    exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} apparaît désormais sur la partie publique.\"}");
   }
 
   // Positionnement "caché" (n'apparaît pas sur la partie publique)
   if ( isset($_REQUEST['cache']) )  {
-    if ( requete('colles',"UPDATE colles SET cache = 1 WHERE id = ${r['id']}",$mysqli) )  {
-      recent($mysqli,2,$r['id'],$mid);
-      $mysqli->query($requete_maj);
-      exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'apparaît plus sur la partie publique mais est toujours disponible ici pour modification ou diffusion.\"}");
-    }
-    exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été caché. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    if ( !requete('colles',"UPDATE colles SET cache = 1 WHERE id = ${r['id']}",$mysqli) )
+      exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été caché. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    recent($mysqli,2,$r['id']);
+    $mysqli->query($requete_maj);
+    exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'apparaît plus sur la partie publique mais est toujours disponible ici pour modification ou diffusion.\"}");
   }
 
   // Suppression
   if ( isset($_REQUEST['supprime']) )  {
-    if ( requete('colles',"DELETE FROM colles WHERE id = ${r['id']}",$mysqli) )  {
-      recent($mysqli,2,$r['id'],$mid);
-      $mysqli->query($requete_maj);
-      exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} a été supprimé.\"}");
-    }
-    exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    if ( !requete('colles',"DELETE FROM colles WHERE id = ${r['id']}",$mysqli) )
+      exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    recent($mysqli,2,$r['id']);
+    $mysqli->query($requete_maj);
+    exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} a été supprimé.\"}");
   }
 }
 
@@ -1087,25 +1083,23 @@
   $r = $resultat->fetch_assoc();
   $resultat->free();
   // Validation des données
-  $texte = $mysqli->real_escape_string($_REQUEST['texte']);
   $cache = intval(isset($_REQUEST['cache']));
-  if ( !strlen($texte) )
+  if ( !( $texte = $mysqli->real_escape_string($_REQUEST['texte']) ) )
     exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été ajouté. Le texte doit être non vide.\"}");
-  if ( requete('colles',"INSERT INTO colles SET texte = '$texte', semaine = $sid, matiere = $mid, cache = $cache",$mysqli) )  {
-    $id = $mysqli->insert_id;
-    $mysqli->query('ALTER TABLE colles ORDER BY matiere,semaine');
-    if ( !$cache )  {
-      // Fabrication des données pour les informations récentes
-      $resultat = $mysqli->query("SELECT nom, cle, colles_protection FROM matieres WHERE id = $mid");
-      $s = $resultat->fetch_assoc();
-      $resultat->free();
-      recent($mysqli,2,$id,$mid,array('titre'=>"Colles du ${r['debut']} en ".$mysqli->real_escape_string($s['nom']), 'lien'=>"colles?${s['cle']}&amp;n=$sid", 'texte'=>$texte, 'matiere'=>$mid, 'protection'=>$s['colles_protection']));
-      // Mise à jour de la matière
-      $mysqli->query("UPDATE matieres SET colles = IF((SELECT id FROM colles WHERE matiere = $mid AND cache = 0 LIMIT 1),1,0) WHERE id = $mid AND colles_protection < 32");
-    }
-    exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} a été ajouté.\"}");
+  if ( !requete('colles',"INSERT INTO colles SET texte = '$texte', semaine = $sid, matiere = $mid, cache = $cache",$mysqli) )
+    exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été ajouté. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+  $id = $mysqli->insert_id;
+  $mysqli->query('ALTER TABLE colles ORDER BY matiere,semaine');
+  if ( !$cache )  {
+    // Fabrication des données pour les informations récentes
+    $resultat = $mysqli->query("SELECT nom, cle, colles_protection FROM matieres WHERE id = $mid");
+    $s = $resultat->fetch_assoc();
+    $resultat->free();
+    recent($mysqli,2,$id,array('titre'=>"Colles du ${r['debut']} en ".$mysqli->real_escape_string($s['nom']), 'lien'=>"colles?${s['cle']}&amp;n=$sid", 'texte'=>$texte, 'matiere'=>$mid, 'protection'=>$s['colles_protection']));
+    // Mise à jour de la matière
+    $mysqli->query("UPDATE matieres SET colles = IF((SELECT id FROM colles WHERE matiere = $mid AND cache = 0 LIMIT 1),1,0) WHERE id = $mid AND colles_protection < 32");
   }
-  exit("{\"etat\":\"nok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} n'a pas été ajouté. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+  exit("{\"etat\":\"ok\",\"message\":\"Le programme de colle de la semaine du ${r['debut']} a été ajouté.\"}");
 }
 
 /////////////////////////////////////////////////////////
@@ -1419,57 +1413,64 @@
 
   // Traitement d'une modification globale (depuis index.php ou pages.php)
   if ( isset($_REQUEST['titre']) && isset($_REQUEST['nom']) && isset($_REQUEST['cle']) && isset($_REQUEST['bandeau']) && isset($_REQUEST['protection']) )  {
-    $titre = strip_tags(trim($mysqli->real_escape_string($_REQUEST['titre'])));
-    $nom = strip_tags(trim($mysqli->real_escape_string($_REQUEST['nom'])));
-    $titre = mb_strtoupper(mb_substr($titre,0,1)).mb_substr($titre,1);
-    $nom = mb_strtoupper(mb_substr($nom,0,1)).mb_substr($nom,1);
+    $titre = mb_strtoupper(mb_substr($titre = trim(strip_tags($mysqli->real_escape_string($_REQUEST['titre']))) ,0,1)).mb_substr($titre,1);
+    $nom = mb_strtoupper(mb_substr($nom = trim(strip_tags($mysqli->real_escape_string($_REQUEST['nom']))),0,1)).mb_substr($nom,1);
     $cle = str_replace(' ','_',strip_tags(trim($mysqli->real_escape_string($_REQUEST['cle']))));
-    if ( !strlen($_REQUEST['titre']) || !strlen($_REQUEST['nom']) || !strlen($_REQUEST['cle']) )
+    if ( !$titre || !$nom || !$cle )
       exit("{\"etat\":\"nok\",\"message\":\"La page <em>${r['nom']}</em> n'a pas été modifiée. Le titre, le nom et la clé doivent être non vides.\"}");
-    // Partie de requête si modification de matière
+    // Partie de requête si modification de matière (impossible si première page)
     // N'existe qu'en provenance de pages.php (et non d'index.php)
     $requete_matiere = ( isset($_REQUEST['matiere']) && in_array($matiere = intval($_REQUEST['matiere']),explode(',',$_SESSION['matieres'])) && ( $matiere != $r['mat'] ) && ( $id > 1 ) ) ? ", mat = $matiere" : '';
     // Vérification que la clé n'existe pas déjà
-    $requete_cle = '';
     if ( $cle != $r['cle'] )  {
-      $resultat = $mysqli->query('SELECT cle FROM pages WHERE mat = '.( strlen($requete_matiere) ? $matiere : $r['mat'] ));
+      $resultat = $mysqli->query('SELECT cle FROM pages WHERE mat = '.( $requete_matiere ? $matiere : $r['mat'] ));
       if ( $resultat->num_rows )  {
         while ( $s = $resultat->fetch_row() )
           if ( $s[0] == $cle )
             exit("{\"etat\":\"nok\",\"message\":\"La page <em>${r['nom']}</em> n'a pas été modifiée. La clé donnée existe déjà. Elle doit être différente de celles des autres pages.\"}"); 
         $resultat->free();
-      $requete_cle = "cle = '$cle',";
       }
     }
     $bandeau = trim($mysqli->real_escape_string($_REQUEST['bandeau']));
     // Génération de la valeur de protection
-    $val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); });
-    if ( !count($val) )
+    if ( !count($val = array_filter($_REQUEST['protection'],function($id) { return ctype_digit($id); })) )
       exit("{\"etat\":\"nok\",\"message\":\"La page <em>${r['nom']}</em> n'a pas été modifiée. La protection d'accès est incorrecte.\"}");
-    if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-      $protection = $val[0];
-    else  {
-      $protection = 32;
-      foreach (array_slice($val,1) as $v) 
-        $protection = $protection-2**($v-1);
-    }
+    $protection = ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32);
     // Écriture
-    if ( requete('pages',"UPDATE pages SET titre = '$titre', nom = '$nom', $requete_cle bandeau = '$bandeau', protection = $protection $requete_matiere WHERE id = $id",$mysqli) )  {
-      if ( strlen($requete_matiere) )  {
-        requete('pages',"UPDATE pages SET ordre = (SELECT COUNT(*) FROM (SELECT id FROM pages AS p WHERE p.mat = $matiere) AS p1) WHERE id = $id",$mysqli);
-        requete('pages',"UPDATE pages SET ordre = (ordre-1) WHERE mat = ${r['mat']} AND ordre > ${r['ordre']}",$mysqli);
-        $mysqli->query('ALTER TABLE pages ORDER BY mat,ordre');
-      }
-      if ( isset($_REQUEST['propagation']) )  {
-        requete('infos',"UPDATE infos SET protection = $protection WHERE page = $id",$mysqli);
-        // Mise à jour des informations récentes
-        requete('recents',"UPDATE recents SET protection = $protection WHERE id IN (SELECT 1000+infos.id FROM infos WHERE page = $id)",$mysqli);
-        rss($mysqli, ( $r['mat'] == 0 ) ? array(0) : array(0,$r['mat']) );
-      }
-      exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"La page <em>${r['nom']}</em> a été modifiée.\"}");
-    }
-    else
+    if ( !requete('pages',"UPDATE pages SET titre = '$titre', nom = '$nom', cle = '$cle', bandeau = '$bandeau', protection = $protection $requete_matiere WHERE id = $id",$mysqli) )
       exit("{\"etat\":\"nok\",\"message\":\"La page <em>${r['nom']}</em> n'a pas été modifiée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
+    // Changement de matière : déplacement des pages sur les matières concernées
+    if ( $requete_matiere )  {
+      requete('pages',"UPDATE pages SET ordre = (SELECT COUNT(*) FROM (SELECT id FROM pages AS p WHERE p.mat = $matiere) AS p1) WHERE id = $id",$mysqli);
+      requete('pages',"UPDATE pages SET ordre = (ordre-1) WHERE mat = ${r['mat']} AND ordre > ${r['ordre']}",$mysqli);
+      // Mise à jour de la table recents, des flux RSS et de l'ordre des pages
+      requete('recents',"UPDATE recents SET matiere = $matiere, 
+                                            titre = CONCAT(SUBSTRING_INDEX(titre,'[',1), ( SELECT CONCAT('[',IF(mat=0,'',CONCAT(m.nom,'/')),p.nom,']')
+                                                                                           FROM pages AS p LEFT JOIN matieres AS m ON mat=m.id WHERE p.id = $id ) )
+                         WHERE type = 1 AND id IN (SELECT id FROM infos WHERE page = $id)",$mysqli);
+      rss($mysqli,array($r['mat'],$matiere),0);
+      $mysqli->query('ALTER TABLE pages ORDER BY mat,ordre');
+    }
+    // Changement de nom : modification de la table recents et des flux RSS (inutile si matière modifiée, impossible si première page)
+    elseif ( ( $nom != $r['nom'] ) && ( $id > 1 ) )  {
+      requete('recents',"UPDATE recents SET titre = CONCAT(SUBSTRING_INDEX(titre,'[',1), ( SELECT CONCAT('[',IF(mat=0,'',CONCAT(m.nom,'/')),p.nom,']')
+                                                                                           FROM pages AS p LEFT JOIN matieres AS m ON mat=m.id WHERE p.id = $id ) )
+                         WHERE type = 1 AND id IN (SELECT id FROM infos WHERE page = $id)",$mysqli);
+      rss($mysqli,$r['mat'],0);
+    }
+    // Changement de clé donc de lien dans la table recents
+    if ( $cle != $r['cle'] )  {
+      requete('recents',"UPDATE recents SET lien = '?$cle' WHERE type = 1 AND id IN (SELECT id FROM infos WHERE page = $id)",$mysqli);
+      rss($mysqli,$r['mat'],0);
+    }
+    // Propagation de la protection : modification des infos
+    if ( isset($_REQUEST['propagation']) )  {
+      requete('infos',"UPDATE infos SET protection = $protection WHERE page = $id",$mysqli);
+      // Mise à jour de la table recents et des flux RSS
+      requete('recents',"UPDATE recents SET protection = $protection WHERE type = 1 AND id IN (SELECT id FROM infos WHERE page = $id)",$mysqli);
+      rss($mysqli,$r['mat'],0);
+    }
+    exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"La page <em>${r['nom']}</em> a été modifiée.\"}");
   }
 
   // Déplacement vers le haut
@@ -1491,8 +1492,10 @@
     if ( $id == 1 )
       exit("{\"etat\":\"nok\",\"message\":\"La page <em>${r['nom']}</em> ne peut pas être supprimée.\"}");
     if ( requete('pages',"DELETE FROM pages WHERE id = $id",$mysqli)
+      && requete('recents',"DELETE FROM recents WHERE type = 1 AND id IN (SELECT id FROM infos WHERE page = $id)",$mysqli)
       && requete('infos',"DELETE FROM infos WHERE page = $id",$mysqli)
-      && requete('pages',"UPDATE pages SET ordre = (ordre-1) WHERE mat = ${r['mat']} AND ordre > ${r['ordre']}",$mysqli) 
+      && requete('pages',"UPDATE pages SET ordre = (ordre-1) WHERE mat = ${r['mat']} AND ordre > ${r['ordre']}",$mysqli)
+      && rss($mysqli,$r['mat'],0)
       && $mysqli->query('ALTER TABLE pages ORDER BY mat,ordre') )
       exit("{\"etat\":\"ok\",\"message\":\"La page <em>${r['nom']}</em> a été supprimée. Les informations contenues ont été supprimées.'\"}");
     exit("{\"etat\":\"nok\",\"message\":\"La page <em>${r['nom']}</em> n'a pas été supprimée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
@@ -1500,7 +1503,9 @@
 
   // Suppression des informations
   if ( isset($_REQUEST['supprime_infos']) )
-    exit( ( requete('infos',"DELETE FROM infos WHERE pages = $id",$mysqli) )
+    exit( requete('recents',"DELETE FROM recents WHERE type = 1 AND id IN (SELECT id FROM infos WHERE page = $id)",$mysqli)
+       && requete('infos',"DELETE FROM infos WHERE page = $id",$mysqli)
+       && rss($mysqli,$r['mat'],0)
       ? "{\"etat\":\"ok\",\"message\":\"Les informations de la page <em>${r['nom']}</em> ont été supprimées.\"}"
       : "{\"etat\":\"nok\",\"message\":\"Les informations de la page <em>${r['nom']}</em> n'ont pas été supprimées. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
 }
@@ -1578,10 +1583,9 @@
 
   // Traitement d'une modification
   if ( isset($_REQUEST['nom']) && isset($_REQUEST['cle']) && isset($_REQUEST['colles_protection']) && isset($_REQUEST['cdt_protection']) && isset($_REQUEST['docs_protection']) && isset($_REQUEST['notes']) && isset($_REQUEST['dureecolle']) )  {
-    $nom = strip_tags(trim($mysqli->real_escape_string($_REQUEST['nom'])));
-    $nom = mb_strtoupper(mb_substr($nom,0,1)).mb_substr($nom,1);
+    $nom = mb_strtoupper(mb_substr($nom = trim(strip_tags($mysqli->real_escape_string($_REQUEST['nom']))),0,1)).mb_substr($nom,1);
     $cle = str_replace(' ','_',strip_tags(trim($mysqli->real_escape_string($_REQUEST['cle']))));
-    if ( !strlen($nom) || !strlen($cle) )
+    if ( !$nom || !$cle )
       exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été modifiée. Le nom et la clé doivent être non vides.\"}");
     // Vérification que la clé n'existe pas déjà
     if ( $cle != $r['cle'] )  {
@@ -1593,28 +1597,32 @@
         $resultat->free();
       }
     }
-    // Génération des valeurs de protection
+    // Génération de la valeur de protection
     $protection = array();
     foreach ( array('colles','cdt','docs') as $fonction )  {
-      $val = array_filter($_REQUEST[$fonction.'_protection'],function($id) { return ctype_digit($id); });
-      if ( !count($val) )
+      if ( !count($val = array_filter($_REQUEST[$fonction.'_protection'],function($id) { return ctype_digit($id); })) )
         exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été modifiée. Une des protections d'accès est incorrecte.\"}");
-      if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-        $protection[$fonction] = $val[0];
-      else  {
-        $p = 32;
-        foreach (array_slice($val,1) as $v) 
-          $p = $p-2**($v-1);
-        $protection[$fonction] = $p;
-      }
+      $protection[$fonction] = ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32);
     }
     // Affichage des notes : 2-> désactivée ; 1-> possible (0 ou 1 dans la base)
     $notes = ( $_REQUEST['notes'] == 2 ) ? '2' : "IF( notes=2, IF((SELECT id FROM notes WHERE matiere = $id LIMIT 1),1,0), notes)";
     $dureecolle = intval($_REQUEST['dureecolle']) ?: 20;
     // Écriture
     if ( requete('matieres',"UPDATE matieres SET nom = '$nom', cle = '$cle', notes = $notes, colles_protection = ${protection['colles']}, cdt_protection = ${protection['cdt']}, docs_protection = ${protection['docs']}, dureecolle = $dureecolle WHERE id = $id",$mysqli) )  {
-      if ( $nom != $r['nom'] )
+      if ( $nom != $r['nom'] )  {
         requete('reps',"UPDATE reps SET nom = '$nom' WHERE matiere = $id AND parent = 0",$mysqli);
+        // Modification de la table recents
+        requete('recents',"UPDATE recents SET titre = ( SELECT CONCAT( IF(LENGTH(i.titre),i.titre,'Information'),' [',m.nom,'/',p.nom,']' )
+                                                        FROM infos AS i LEFT JOIN pages AS p ON page=p.id LEFT JOIN matieres AS m ON mat=m.id WHERE i.id = recents.id )
+                           WHERE type = 1 AND matiere = $id",$mysqli);
+        requete('recents',"UPDATE recents SET protection = ${protection['colles']}, ".( ( $cle != $r['cle'] ) ? "lien = CONCAT('colles?$cle&amp;n=',SUBSTRING_INDEX(lien,'&',-1))," : '')."
+                                              titre = CONCAT( SUBSTRING_INDEX(titre,' ',4), ' en $nom' )
+                           WHERE type = 2 AND matiere = $id",$mysqli);
+        requete('recents',"UPDATE recents SET texte = ( SELECT CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' ))
+                                                        FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) WHERE d.id = recents.id GROUP BY d.id )
+                                          WHERE type = 3 AND matiere = $id",$mysqli);
+        rss($mysqli,$r['mat'],0);
+      }
       if ( $protection['docs'] != $r['docs_protection'] )
         requete('reps',"UPDATE reps SET protection = ${protection['docs']} WHERE matiere = $id AND parent = 0",$mysqli);
       exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"La matière <em>${r['nom']}</em> a été modifiée.\"}");
@@ -1627,52 +1635,68 @@
   if ( isset($_REQUEST['supprime']) )  {
     if ( $r['max'] == 1 )
       exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été supprimée. Il faut obligatoirement en garder au moins une.\"}");
+    $resultat->$mysql_query("SELECT id FROM reps WHERE parent = 0 AND matiere = $id");
+    $rid = $resultat->fetch_row()[0];
+    $resultat->free();
     if ( requete('matieres',"DELETE FROM matieres WHERE id = $id",$mysqli) 
       && requete('matieres',"UPDATE matieres SET ordre = (ordre-1) WHERE ordre > ${r['ordre']}",$mysqli)
       && requete('colles',"DELETE FROM colles WHERE matiere = $id",$mysqli)
+      && requete('recents',"DELETE FROM recents WHERE type = 2 AND matiere = $id",$mysqli)
       && requete('cdt',"DELETE FROM cdt WHERE matiere = $id",$mysqli)
       && requete('cdt-types',"DELETE FROM `cdt-types` WHERE matiere = $id",$mysqli)
       && requete('cdt-seances',"DELETE FROM `cdt-seances` WHERE matiere = $id",$mysqli)
       && requete('notes',"DELETE FROM notes WHERE matiere = $id",$mysqli)
-      && requete('reps',"UPDATE reps SET matiere = 0 WHERE matiere = $id",$mysqli)
-      && requete('docs',"UPDATE docs SET matiere = 0 WHERE matiere = $id",$mysqli)
+      && requete('reps',"UPDATE reps SET matiere = 0, parent = 1, parents = '0,1' WHERE id = $rid",$mysqli)
+      && requete('reps',"UPDATE reps SET matiere = 0, parents = CONCAT('0,1',SUBSTRING(parents,2)) WHERE matiere = $id AND id != $rid",$mysqli)
+      && requete('docs',"UPDATE docs SET matiere = 0, parents = CONCAT('0,1',SUBSTRING(parents,2)) WHERE matiere = $id",$mysqli)
+      && requete('recents',"UPDATE recents SET matiere = 0 WHERE type = 3 AND matiere = $id",$mysqli)
       && requete('pages',"UPDATE pages SET mat = 0 WHERE mat = $id",$mysqli)
+      && requete('recents',"UPDATE recents SET matiere = 0, titre = ( SELECT CONCAT(IF(LENGTH(i.titre),i.titre,'Information'),' [',p.nom,']') 
+                                                                      FROM infos AS i LEFT JOIN pages AS p ON page=p.id WHERE i.id = recents.id )
+                            WHERE type = 1 AND matiere = $id",$mysqli)
       && requete('agenda',"UPDATE agenda SET matiere = 0 WHERE matiere = $id",$mysqli)
-      && requete('utilisateurs',"UPDATE utilisateurs SET matieres = TRIM(TRAILING ',' FROM REPLACE(CONCAT(matieres,','),',$id,',',')) ",$mysqli) )
+      && requete('recents',"UPDATE recents SET matiere = 0 WHERE type = 4 AND matiere = $id",$mysqli)
+      && requete('utilisateurs',"UPDATE utilisateurs SET matieres = TRIM(TRAILING ',' FROM REPLACE(CONCAT(matieres,','),',$id,',',')) ",$mysqli)
+      && rss($mysqli,0,0) )
       exit("{\"etat\":\"ok\",\"message\":\"La matière <em>${r['nom']}</em> a été supprimée. Les répertoires, documents, pages d'informations et éléments d'agenda associés à la matières n'ont pas été supprimés mais déplacés dans le contexte «&nbsp;général&nbsp;»'\"}");
     exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été supprimée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 
   // Suppression des programmes de colles d'une matière
   if ( isset($_REQUEST['supprime_colles']) )
-    exit( ( requete('colles',"DELETE FROM colles WHERE matiere = $id",$mysqli) && requete('matieres',"UPDATE matieres SET colles = 0 WHERE id = $id",$mysqli) )
+    exit( requete('colles',"DELETE FROM colles WHERE matiere = $id",$mysqli)
+       && requete('matieres',"UPDATE matieres SET colles = 0 WHERE id = $id",$mysqli)
+       && requete('recents',"DELETE FROM recents WHERE type = 2 AND matiere = $id",$mysqli)
+       && rss($mysqli,$id,0)
       ? "{\"etat\":\"ok\",\"message\":\"Les programmes de colle de la matière <em>${r['nom']}</em> ont été supprimés.\"}"
       : "{\"etat\":\"nok\",\"message\":\"Les programmes de colle de la matière <em>${r['nom']}</em> n'ont pas été supprimés. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
   
   // Suppression du cahier de texte d'une matière
   if ( isset($_REQUEST['supprime_cdt']) )
-    exit( ( requete('cdt',"DELETE FROM cdt WHERE matiere = $id",$mysqli) && requete('matieres',"UPDATE matieres SET cdt = 0 WHERE id = $id",$mysqli) )
+    exit( requete('cdt',"DELETE FROM cdt WHERE matiere = $id",$mysqli) && requete('matieres',"UPDATE matieres SET cdt = 0 WHERE id = $id",$mysqli)
       ? "{\"etat\":\"ok\",\"message\":\"Le cahier de texte de la matière <em>${r['nom']}</em> a été supprimé.\"}"
       : "{\"etat\":\"nok\",\"message\":\"Le cahier de texte de la matière <em>${r['nom']}</em> n'a pas été supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
 
   // Suppression des notes d'une matière
   if ( isset($_REQUEST['supprime_notes']) )
-    exit( ( requete('notes',"DELETE FROM notes WHERE matiere = $id",$mysqli) && requete('matieres',"UPDATE matieres SET notes = 0 WHERE id = $id",$mysqli) )
+    exit( requete('notes',"DELETE FROM notes WHERE matiere = $id",$mysqli) && requete('matieres',"UPDATE matieres SET notes = 0 WHERE id = $id",$mysqli)
       ? "{\"etat\":\"ok\",\"message\":\"Les notes de la matière <em>${r['nom']}</em> ont été supprimées.\"}"
       : "{\"etat\":\"nok\",\"message\":\"Les notes de la matière <em>${r['nom']}</em> n'ont pas été supprimées. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
 
   // Suppression des documents d'une matière
   if ( isset($_REQUEST['supprime_docs']) )  {
-    if ( requete('reps',"DELETE FROM reps WHERE matiere = $id AND parent > 0",$mysqli) )  {
+    if ( requete('reps',"DELETE FROM reps WHERE matiere = $id AND parent > 0",$mysqli)
+      && requete('docs',"DELETE FROM docs WHERE matiere = $id",$mysqli)
+      && requete('matieres',"UPDATE matieres SET docs = 0 WHERE id = $id",$mysqli)
+      && requete('recents',"DELETE FROM recents WHERE type = 3 AND matiere = $id",$mysqli)
+      && rss($mysqli,$id,0) )  {
       // Suppression physique
       $resultat = $mysqli->query("SELECT lien FROM docs WHERE matiere = $id");
       if ( $resultat->num_rows )  {
         while ( $r = $resultat->fetch_row() )
           exec("rm -rf documents/${r[0]}");
         $resultat->free();
-        requete('docs',"DELETE FROM docs WHERE matiere = $id",$mysqli);
       }
-      requete('matieres',"UPDATE matieres SET docs = 0 WHERE id = $id",$mysqli);
       exit("{\"etat\":\"ok\",\"message\":\"Les répertoires et documents de la matière <em>${r['nom']}</em> ont été supprimés.\"}");
     }
     exit("{\"etat\":\"nok\",\"message\":\"Les documents de la matière <em>${r['nom']}</em> n'ont pas été supprimés. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
@@ -1732,76 +1756,71 @@
 //////////////////////////////////////////
 // Modification d'un utilisateur unique //
 //////////////////////////////////////////
-elseif ( ( $action == 'utilisateur' ) && isset($_REQUEST['modif']) && in_array($modif = $_REQUEST['modif'],array('mailenvoi','prefs','desactive','active','supprutilisateur','validutilisateur')) && isset($_REQUEST['id']) && ctype_digit($id = $_REQUEST['id']) )  {
+elseif ( ( $action == 'utilisateur' ) && isset($_REQUEST['modif']) && in_array($modif = $_REQUEST['modif'],array('prefs','desactive','active','supprutilisateur','validutilisateur')) && isset($_REQUEST['id']) && ctype_digit($id = $_REQUEST['id']) )  {
 
   // Vérification que l'identifiant est valide
   // Attention, les valeurs "valide", "demande" et "invitation" sont des chaines de caractères égales à '0' ou '1'.
-  $resultat = $mysqli->query("SELECT nom, prenom, login, matieres, mail, (LENGTH(mdp)=40) AS valide, (LEFT(mdp,1)='*') AS demande, (LENGTH(mdp)=1) AS invitation, autorisation, mailenvoi, mailexp, mailliste, mailcopie FROM utilisateurs WHERE id = $id");
+  $resultat = $mysqli->query("SELECT nom, prenom, login, matieres, mail, (LENGTH(mdp)=40) AS valide, (LEFT(mdp,1)='*') AS demande, (LENGTH(mdp)=1) AS invitation, autorisation, mailexp, mailcopie FROM utilisateurs WHERE id = $id");
   if ( !$resultat->num_rows )
     exit('{"etat":"nok","message":"Identifiant non valide"}');  
   $r = $resultat->fetch_assoc();
   $resultat->free();
-  $compte = ( strlen($r['nom'].$r['prenom']) ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
+  $compte = ( $r['nom'].$r['prenom'] ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
   switch ( $modif )  {
 
-    // Modification de la possibilité d'envoyer des mails seulement
-    case 'mailenvoi': {
-      $val = intval( isset($_REQUEST['val']) && $_REQUEST['val'] );
-      if ( $r['autorisation'] == 1 )
-        exit('{"etat":"nok","message":"Un compte de type invité ne peut pas envoyer des courriels."}');
-      if ( $val == $r['mailenvoi'] )
-        exit('{"etat":"ok","message":"Ce réglage était déjà celui en place. Aucune modification n\'a été effectuée."}');
-      if ( $val && !strlen($r['mail']) )
-        exit('{"etat":"nok","message":"Un compte ne peut envoyer de courriel sans adresse électronique valide."}');
-      if ( requete('utilisateurs',"UPDATE utilisateurs SET mailenvoi = $val, mailexp = IF($val AND mailexp = '',CONCAT(prenom,' ',nom),mailexp) WHERE id = $id",$mysqli) )
-        exit('{"etat":"ok","message":"Les préférences d\'envoi de mail '.$compte.' ont été modifiées."}');
-      exit('{"etat":"nok","message":"Les préférences d\'envoi de mail '.$compte.' n\'ont pas été modifiées. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
-    }
-
     // Modification des données du compte (venant du formulaire de utilisateurs.php)
     case 'prefs': {
-      $modifications = array_diff_assoc( array( 'nom'=>trim($_REQUEST['nom']), 'prenom'=>trim($_REQUEST['prenom']), 'login'=>trim($_REQUEST['login']), 'mail'=>mb_strtolower(trim($_REQUEST['mail1'])), 'mailexp'=>trim(isset($_REQUEST['mailexp']) ? isset($_REQUEST['mailexp']) : ''), 'mailenvoi'=>intval(isset($_REQUEST['mailenvoi'])), 'mailcopie'=>intval(isset($_REQUEST['mailcopie'])), 'mailliste'=>intval(isset($_REQUEST['mailliste'])) ), $r);
-      if ( !$modifications )
-        exit('{"etat":"ok","message":"Les valeurs fournies étaient celles déjà enregistrées. Aucune modification n\'a été effectuée."}');
-      $requete = '';
-      if ( isset($modifications['nom']) && strlen($nom = mb_convert_case(strip_tags($mysqli->real_escape_string($modifications['nom'])),MB_CASE_TITLE)) )
-        $requete .= ", nom = '$nom'";
-      if ( isset($modifications['prenom']) && strlen($prenom = mb_convert_case(strip_tags($mysqli->real_escape_string($modifications['prenom'])),MB_CASE_TITLE)) )
-        $requete .= ", prenom = '$prenom'";
-      if ( isset($modifications['login']) && strlen($login = mb_strtolower(str_replace(' ','_',$modifications['login']))) )  {
-        // Vérification que le login n'existe pas déjà
-        $resultat = $mysqli->query("SELECT GROUP_CONCAT(login) FROM utilisateurs WHERE id != $id");
-        $s = $resultat->fetch_row();
-        $resultat->free();
-        if ( !in_array($login,explode(',',$s[0])) )
-          $requete .= ', login = \''.$mysqli->real_escape_string($login).'\'';
+      // Fonction de fabrication de la partie modifiante de la requête
+      function fabriqueupdate($requete,$mysqli)  {
+        $chaine = '';
+        foreach ($requete as $champ=>$val)
+          $chaine .= ",$champ = '".$mysqli->real_escape_string($val).'\'';
+        return substr($chaine,1);
+      }
+      // Valeurs à modifier
+      $requete = array_diff_assoc( array( 'nom'=>trim($_REQUEST['nom']), 'prenom'=>trim($_REQUEST['prenom']), 'login'=>trim($_REQUEST['login']), 'mail'=>mb_strtolower(trim($_REQUEST['mail1'])), 'mailexp'=>(trim($_REQUEST['mailexp']) ?? ''), 'mailcopie'=>intval(isset($_REQUEST['mailcopie'])) ), $r);
+      if ( isset($requete['nom']) && !($nom = mb_convert_case(strip_tags($requete['nom']),MB_CASE_TITLE)) )
+        unset($requete['nom']);
+      if ( isset($requete['prenom']) && !($prenom = mb_convert_case(strip_tags($requete['prenom']),MB_CASE_TITLE)) )
+        unset($requete['prenom']);
+      if ( isset($requete['login']) )  {
+        if ( !($login = mb_strtolower(str_replace(' ','_',$requete['login']))) )
+          unset($requete['login']);
+        else  {
+          // Vérification que le login n'existe pas déjà
+          $resultat = $mysqli->query("SELECT GROUP_CONCAT(login) FROM utilisateurs WHERE id != $id");
+          $s = $resultat->fetch_row();
+          $resultat->free();
+          if ( in_array($login,explode(',',$s[0])) )
+            unset($requete['login']);
+        }
       }
-      if ( isset($modifications['mail']) && filter_var($mail = $modifications['mail'],FILTER_VALIDATE_EMAIL) && isset($_REQUEST['mail2']) )  {
-        if ( $mail != mb_strtolower(trim($_REQUEST['mail2'])) )
+      if ( isset($requete['mail']) )  {
+        if ( !filter_var($mail = $requete['mail'],FILTER_VALIDATE_EMAIL) || !isset($_REQUEST['mail2']) )
+          unset($requete['mail']);
+        elseif ( $mail != mb_strtolower(trim($_REQUEST['mail2'])) )
           exit('{"etat":"nok","message":"Les préférences '.$compte.' n\'ont pas été modifiées, les deux adresses électroniques saisies ne sont pas identiques."}');
-        // Vérification que l'adresse n'existe pas déjà
-        $resultat = $mysqli->query("SELECT GROUP_CONCAT(mail) FROM utilisateurs WHERE id != $id AND mail > ''");
-        $s = $resultat->fetch_row();
-        $resultat->free();
-        if ( !in_array($mail,explode(',',$s[0])) )
-          $requete .= ', mail = \''.$mysqli->real_escape_string($r['mail'] = $mail).'\'';
+        else  {
+          // Vérification que l'adresse n'existe pas déjà
+          $resultat = $mysqli->query("SELECT GROUP_CONCAT(mail) FROM utilisateurs WHERE id != $id AND mail > ''");
+          $s = $resultat->fetch_row();
+          $resultat->free();
+          if ( in_array($mail,explode(',',$s[0])) )
+            unset($requete['mail']);
+        }
       }
-      if ( isset($modifications['mailenvoi']) && ( $r['autorisation'] > 1 ) && ( !$modifications['mailenvoi'] || strlen($r['mail']) ) )
-        $requete .= ', mailenvoi = \''.( $r['mailenvoi'] = $modifications['mailenvoi'] ).'\'';
-      if ( $r['mailenvoi'] )  {
-        if ( isset($modifications['mailexp']) && strlen($mailexp = strip_tags($mysqli->real_escape_string($modifications['mailexp']))) )
-          $requete .= ", mailexp = '$mailexp'";
-        elseif ( !strlen($r['mailexp']) )
-          $requete .= ', mailexp = CONCAT(prenom,\' \',nom)';
-        if ( isset($modifications['mailcopie']) )
-          $requete .= ", mailcopie = ${modifications['mailcopie']}";
-        if ( isset($modifications['mailliste']) && ( $r['autorisation'] > 2 ) )
-          $requete .= ", mailliste = ${modifications['mailliste']}";
-      }
-      if ( !strlen($requete) )
-        exit('{"etat":"nok","message":"Les préférences '.$compte.' n\'ont pas été modifiées, les valeurs saisies sont identiques à celles existantes."}');
-      if( requete('utilisateurs','UPDATE utilisateurs SET '.substr($requete,2)." WHERE id = $id",$mysqli) )
+      if ( isset($requete['mailexp']) && !($mailexp = strip_tags($requete['mailexp'])) )
+        unset($requete['mailexp']);
+      if ( !$requete )
+        exit('{"etat":"ok","message":"Les valeurs fournies étaient celles déjà enregistrées. Aucune modification n\'a été effectuée."}');
+      if( requete('utilisateurs','UPDATE utilisateurs SET '.fabriqueupdate($requete)." WHERE id = $id",$mysqli) )  {
+        // Si interface globale activée, mise à jour
+        if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+          include("${interfaceglobale}majutilisateurs.php");
+          majutilisateurs($id,$requete);
+        }
         exit($_SESSION['message'] = '{"etat":"ok","message":"Les préférences '.$compte.' ont été modifiées."}');
+      }
       exit('{"etat":"nok","message":"Les préférences '.$compte.' n\'ont pas été modifiées. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
     }
 
@@ -1811,8 +1830,14 @@
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le compte $compte est déjà actuellement désactivé.\"}");
       if ( ( $r['demande'] == 1 ) || ( $r['invitation'] == 1 ) )
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le compte $compte n'est pas actuellement désactivable.\"}");
-      if ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = CONCAT('!',mdp) WHERE id = $id",$mysqli) )
+      if ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = CONCAT('!',mdp) WHERE id = $id",$mysqli) )  {
+        // Si interface globale activée, mise à jour
+        if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+          include("${interfaceglobale}majutilisateurs.php");
+          majutilisateurs($id,'désactivation');
+        }
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Compte $compte désactivé\"}");
+      }
       exit("{\"etat\":\"nok\",\"message\":\"La désactivation du compte $compte n'a pas été réalisée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
     }
 
@@ -1822,8 +1847,14 @@
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le compte $compte est déjà actuellement activé.\"}");
       if ( ( $r['demande'] == 1 ) || ( $r['invitation'] == 1 ) )
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Le compte $compte n'est pas actuellement activable.\"}");
-      if ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = SUBSTR(mdp,2) WHERE id = $id",$mysqli) )
+      if ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = SUBSTR(mdp,2) WHERE id = $id",$mysqli) )  {
+        // Si interface globale activée, mise à jour
+        if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+          include("${interfaceglobale}majutilisateurs.php");
+          majutilisateurs($id,'activation');
+        }
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Compte $compte réactivé\"}");
+      }
       exit("{\"etat\":\"nok\",\"message\":\"La réactivation du compte $compte n'a pas été réalisée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
     }
 
@@ -1843,12 +1874,17 @@
           $resultat->free();
           if ( !is_null($s[0]) )  {
             requete('notes',"DELETE FROM notes WHERE eleve = $id",$mysqli);
-            requete('heurescolles',"DELETE heurescolles FROM heurescolles LEFT JOIN notes ON heurescolles.id=notes.heure
+            requete('heurescolles',"DELETE FROM heurescolles LEFT JOIN notes ON heurescolles.id=notes.heure
                                     WHERE FIND_IN_SET(heurescolles.id,'${s[0]}') AND notes.id IS NULL",$mysqli);
             requete('heurescolles',"UPDATE heurescolles SET duree = duree-(SELECT dureecolle FROM matieres WHERE matieres.id = heurescolles.matiere) 
                                     WHERE FIND_IN_SET(heurescolles.id,'${s[0]}') AND releve = 0",$mysqli);
           }
         }
+        // Si interface globale activée, mise à jour
+        if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+          include("${interfaceglobale}majutilisateurs.php");
+          majutilisateurs($id,'suppression');
+        }
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Compte $compte supprimé\"}");
       }
       exit("{\"etat\":\"nok\",\"message\":\"La suppression du compte $compte n'a pas été réalisée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
@@ -1862,7 +1898,7 @@
         mail($r['mail'],'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Compte validé').'?=',
 "Bonjour
 
-Vous avez rempli une demande de création de compte sur le Cahier de Prépa <https://$site>, correspondant à l'identifiant ${r['login']}.
+Vous avez rempli une demande de création de compte sur le Cahier de Prépa <https://$domaine$chemin>, correspondant à l'identifiant ${r['login']}.
 
 Cette demande vient de recevoir une réponse favorable de la part de l'équipe pédagogique en charge du site. Vous pouvez donc désormais vous connecter avec votre identifiant et votre mot de passe.
 
@@ -1872,6 +1908,11 @@
 -- 
 Cahier de Prépa
 ",'From: =?UTF-8?B?'.base64_encode('Cahier de Prépa')."?= <$mailadmin>\r\nContent-type: text/plain; charset=UTF-8","-f$mailadmin");
+        // Si interface globale activée, mise à jour
+        if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+          include("${interfaceglobale}majutilisateurs.php");
+          majutilisateurs($id,'activation');
+        }
         exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"Demande de compte $compte accordée. L'élève a été prévenu par courriel.\"}");
       }
       exit("{\"etat\":\"nok\",\"message\":\"La validation du compte $compte n'a pas été réalisée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');
@@ -1882,54 +1923,54 @@
 //////////////////////////////////////////
 // Modification multiple d'utilisateurs // 
 //////////////////////////////////////////
-elseif ( ( $action == 'utilisateurs' ) && isset($_REQUEST['modif']) && in_array($modif = $_REQUEST['modif'],array('mailenvoi','desactive','active','supprutilisateur','validutilisateur')) && isset($_REQUEST['ids']) && strlen($ids = implode(',',array_filter(explode(',',$_REQUEST['ids']),function($id) { return ctype_digit($id); }))) )  {
+elseif ( ( $action == 'utilisateurs' ) && isset($_REQUEST['modif']) && in_array($modif = $_REQUEST['modif'],array('desactive','active','supprutilisateur','validutilisateur')) && isset($_REQUEST['ids']) && strlen($ids = implode(',',array_filter(explode(',',$_REQUEST['ids']),function($id) { return ctype_digit($id); }))) )  {
 
   // Vérification que les identifiants sont valides
   // Attention, les valeurs "valide", "demande" et "invitation" sont des chaines de caractères égales à '0' ou '1'.
-  $resultat = $mysqli->query("SELECT id, nom, prenom, login, mail, (LENGTH(mdp)=40) AS valide, (LEFT(mdp,1)='*') AS demande, (LENGTH(mdp)=1) AS invitation, autorisation, mailenvoi, mailexp, mailliste, mailcopie FROM utilisateurs WHERE FIND_IN_SET(id,'$ids')");
+  $resultat = $mysqli->query("SELECT id, nom, prenom, login, mail, (LENGTH(mdp)=40) AS valide, (LEFT(mdp,1)='*') AS demande, (LENGTH(mdp)=1) AS invitation, autorisation, mailexp, mailcopie FROM utilisateurs WHERE FIND_IN_SET(id,'$ids')");
   if ( !$resultat->num_rows )
     exit('{"etat":"nok","message":"Identifiants non valides"}');
   $message = array('ok'=>'','nok'=>'');
   switch ( $modif )  {
 
-    // Modification de la possibilité d'envoyer des mails seulement
-    case 'mailenvoi': {
-      $val = intval( isset($_REQUEST['val']) && ( $_REQUEST['val'] == 1 ) );
-      while ( $r = $resultat->fetch_assoc() )  {
-        $compte = ( strlen($r['nom'].$r['prenom']) ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
-        if ( ( $r['autorisation'] == 1 ) || ( $val == $r['mailenvoi'] ) || ( $val && !strlen($r['mail']) ) )
-          $message['nok'] .= "Les préférences d'envoi de mail $compte n'ont pas été modifiées, car le compte ne peut envoyer de mail ou en envoie déjà.<br>";
-        elseif ( requete('utilisateurs',"UPDATE utilisateurs SET mailenvoi = $val, mailexp = IF($val AND mailexp = '',CONCAT(prenom,' ',nom),mailexp) WHERE id = ${r['id']}",$mysqli) )
-          $message['ok'] .= "Les préférences d'envoi de mail $compte ont été modifiées.<br>";
-        else
-          $message['nok'] .= "Les préférences d'envoi de mail $compte n'ont pas été modifiées. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»<br>';
-      }
-    }
-
     // Désactivation
     case 'desactive': {
       while ( $r = $resultat->fetch_assoc() )  {
         $compte = ( strlen($r['nom'].$r['prenom']) ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
         if ( ( $r['demande'] == 1 ) || ( $r['invitation'] == 1 ) || ( $r['valide'] == 0 ) )
           $message['nok'] .= "Le compte $compte n'a pas été désactivé, car il l'est déjà ou ne peut pas l'être.<br>";
-        elseif ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = CONCAT('!',mdp) WHERE id = ${r['id']}",$mysqli) )
+        elseif ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = CONCAT('!',mdp) WHERE id = ${r['id']}",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+            include_once("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($r['id'],'désactivation');
+          }
           $message['ok'] .= "Le compte $compte a été désactivé.<br>";
+        }
         else
           $message['nok'] .= "Le compte $compte n'a pas été désactivé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»<br>';
       }
+      break;
     }
 
     // Réactivation
     case 'active': {
       while ( $r = $resultat->fetch_assoc() )  {
-        $compte = ( strlen($r['nom'].$r['prenom']) ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
+        $compte = ( $r['nom'].$r['prenom'] ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
         if ( ( $r['demande'] == 1 ) || ( $r['invitation'] == 1 ) || ( $r['valide'] == 1 ) )
           $message['nok'] .= "Le compte $compte n'a pas été activé, car il l'est déjà ou ne peut pas l'être.<br>";
-        elseif ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = SUBSTR(mdp,2) WHERE id = ${r['id']}",$mysqli) )
+        elseif ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = SUBSTR(mdp,2) WHERE id = ${r['id']}",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+            include_once("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($r['id'],'activation');
+          }
           $message['ok'] .= "Le compte $compte a été réactivé.<br>";
+        }
         else
           $message['nok'] .= "Le compte $compte n'a pas été réactivé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»<br>';
       }
+      break;
     }
 
     // Suppression
@@ -1938,20 +1979,23 @@
         $compte = ( strlen($r['nom'].$r['prenom']) ) ? "de <em>${r['prenom']} ${r['nom']}</em>" : "<em>${r['login']}</em>";
         if ( requete('utilisateurs',"DELETE FROM utilisateurs WHERE id = ${r['id']}",$mysqli)
           && requete('groupes',"UPDATE groupes SET utilisateurs = TRIM(BOTH ',' FROM REPLACE(CONCAT(',',utilisateurs,','),',${r['id']},',',')) WHERE FIND_IN_SET(${r['id']},utilisateurs)",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+            include_once("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($r['id'],'suppression');
+          }
           // Recherche des notes : cas des colleurs/profs
           if ( $r['autorisation'] > 2 )  {
-            requete('notes',"DELETE FROM notes WHERE colleur = $id",$mysqli);
-            requete('heurescolles',"DELETE FROM heurescolles WHERE colleur = $id",$mysqli);
+            requete('notes',"DELETE FROM notes WHERE colleur = ${r['id']}",$mysqli);
+            requete('heurescolles',"DELETE FROM heurescolles WHERE colleur = ${r['id']}",$mysqli);
           }
           // Recherche des notes : cas des élèves
           elseif ( $r['autorisation'] == 2 )  {
-            $resultat = $mysqli->query("SELECT GROUP_CONCAT(heure) FROM notes WHERE eleve = $id");
-            $s = $resultat->fetch_row();
-            $resultat->free();
+            $resultat2 = $mysqli->query("SELECT GROUP_CONCAT(heure) FROM notes WHERE eleve = ${r['id']}");
+            $s = $resultat2->fetch_row();
+            $resultat2->free();
             if ( !is_null($s[0]) )  {
-              requete('notes',"DELETE FROM notes WHERE eleve = $id",$mysqli);
-              requete('heurescolles',"DELETE heurescolles FROM heurescolles LEFT JOIN notes ON heurescolles.id=notes.heure
-                                      WHERE FIND_IN_SET(heurescolles.id,'${s[0]}') AND notes.id IS NULL",$mysqli);
+              requete('notes',"DELETE FROM notes WHERE eleve = ${r['id']}",$mysqli);
               requete('heurescolles',"UPDATE heurescolles SET duree = duree-(SELECT dureecolle FROM matieres WHERE matieres.id = heurescolles.matiere) 
                                       WHERE FIND_IN_SET(heurescolles.id,'${s[0]}') AND releve = 0",$mysqli);
             }
@@ -1961,6 +2005,10 @@
         else
           $message['nok'] .= "Le compte $compte n'a pas été supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»<br>';
       }
+      // Nettoyage des groupes et des heures de colles
+      requete('heurescolles',"DELETE FROM heurescolles LEFT JOIN notes ON heurescolles.id=notes.heure WHERE notes.id IS NULL",$mysqli);
+      requete('groupes',"DELETE FROM groupes WHERE utilisateurs = ''",$mysqli);
+      break;
     }
 
     // Validation d'une demande
@@ -1970,10 +2018,16 @@
         if ( $r['demande'] == 0 )
           $message['nok'] .= "La demande $compte a déjà été validée.<br>";
         elseif ( requete('utilisateurs',"UPDATE utilisateurs SET mdp = SUBSTR(mdp,2) WHERE id = ${r['id']}",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( ( $r['autorisation'] > 1 ) && $interfaceglobale )  {
+            include_once("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($r['id'],'activation');
+          }
+          // Envoi de courriel de confirmation
           mail($r['mail'],'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Compte validé').'?=',
 "Bonjour
 
-Vous avez rempli une demande de création de compte sur le Cahier de Prépa <https://$site>, correspondant à l'identifiant ${r['login']}.
+Vous avez rempli une demande de création de compte sur le Cahier de Prépa <https://$domaine$chemin>, correspondant à l'identifiant ${r['login']}.
 
 Cette demande vient de recevoir une réponse favorable de la part de l'équipe pédagogique en charge du site. Vous pouvez donc désormais vous connecter avec votre identifiant et votre mot de passe.
 
@@ -2060,6 +2114,11 @@
           if ( requete('utilisateurs',"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mdp = '".sha1($mdp.$u[2])."', autorisation = $autorisation, matieres = '$matieres', timeout = 900",$mysqli) )  {
             $message .= "<br>Ligne $i : ok (<strong>$prenom $nom</strong>, identifiant $login)";
             $n = $n+1;
+            // Si interface globale activée, mise à jour
+            if ( $interfaceglobale )  {
+              include_once("${interfaceglobale}majutilisateurs.php");
+              majutilisateurs($mysqli->insert_id,"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '', mdp = '".sha1($mdp.$u[2])."', autorisation = $autorisation");
+            }
           }
           else
             $message .= "<br>Ligne $i : erreur MySQL n°".$mysqli->errno.' «'.$mysqli->error.'»';
@@ -2075,22 +2134,24 @@
           elseif ( !filter_var($mail,FILTER_VALIDATE_EMAIL) )
             $message .= "<br>Ligne $i : adresse électronique non valide (<strong>$prenom $nom</strong>)";
           else  {
-            $mailenvoi = intval(isset($_REQUEST['mailenvoi']));
-            $mailexp = $mailenvoi ? "$prenom $nom" : '';
-            $mailliste = ( $mailenvoi && ( $autorisation > 2 ) ) ? intval(isset($_REQUEST['mailliste'])) : 0;
-            if ( requete('utilisateurs',"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '$mail', mdp = '?', autorisation = $autorisation, matieres = '$matieres', timeout = 900, mailenvoi = $mailenvoi, mailcopie = $mailenvoi, mailexp = '$mailexp', mailliste = $mailliste",$mysqli) )  {
+            if ( requete('utilisateurs',"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '$mail', mdp = '?', autorisation = $autorisation, matieres = '$matieres', timeout = 900, mailexp = '$prenom $nom'",$mysqli) )  {
               $message .= "<br>Ligne $i : ok (<strong>$prenom $nom</strong>, identifiant $login)";
               $n = $n+1;
-              $lien = 'https://'.$site.'/gestioncompte?invitation&mail='.str_replace('@','__',$mail).'&p='.sha1($site.$mdp.$mail);
+              // Si interface globale activée, mise à jour
+              if ( $interfaceglobale )  {
+                include_once("${interfaceglobale}majutilisateurs.php");
+                majutilisateurs($mysqli->insert_id,"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '$mail', mdp = '?', autorisation = $autorisation");
+              }
               // Récupération de l'adresse électronique du professeur connecté
               $resultat = $mysqli->query("SELECT mail FROM utilisateurs WHERE id = ${_SESSION['id']}");
               $s = $resultat->fetch_row();
               $resultat->free();
               $returnpath = $s[0] ?: $mailadmin;
+              $lien = "https://$domaine${chemin}gestioncompte?invitation&mail=".str_replace('@','__',$mail).'&p='.sha1($chemin.$mdp.$mail);
               mail($mail,'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Invitation').'?=',
 "Bonjour
 
-L'équipe pédagogique en charge du Cahier de Prépa <https://$site> vous invite à les rejoindre.
+L'équipe pédagogique en charge du Cahier de Prépa <https://$domaine$chemin> vous invite à les rejoindre.
 
 S'il s'agit d'une erreur, merci d'ignorer simplement ce courriel.
 
@@ -2300,17 +2361,22 @@
   // Récupérations des donnees envoyées
   $colles = ( isset($_REQUEST['colles']) ) ? $_REQUEST['colles'] : array();
   $vacances = ( isset($_REQUEST['vacances']) ) ? $_REQUEST['vacances'] : array();
+  // Valeur maximale du code vacances
+  $resultat = $mysqli->query('SELECT MAX(id) FROM vacances');
+  $vmax = $resultat->fetch_row()[0];
+  $resultat->free();
   // Comparaison et modification
   $modif = array();
   $resultat = $mysqli->query('SELECT id, colle, vacances, DATE_FORMAT(debut,\'%d/%m/%Y\') AS debut FROM semaines');
   while ( $r = $resultat->fetch_assoc() )  {
-    $v = intval( ( ctype_digit($v = $vacances[$r['id']]) && ( $v < 5 ) ) ? $v : 0 );
+    $v = intval( ( ctype_digit($v = $vacances[$r['id']]) && ( $v <= $vmax ) ) ? $v : 0 );
     $c = intval( isset($colles[$r['id']]) && !$v );
     if ( ( $c != $r['colle'] ) || ( $v != $r['vacances'] ) )  {
       requete('semaines',"UPDATE semaines SET colle = $c, vacances = $v WHERE id = ${r['id']}",$mysqli);
       $modif[] = "semaine du ${r['debut']}";
     }
   }
+  $resultat->free();
   // Message à afficher
   exit( $modif ? '{"etat":"ok","message":"Les modifications ont été réalisées ('.implode(', ',$modif).')."}' : '{"etat":"ok","message":"Aucune modification n\'a été réalisée."}');
 }
@@ -2327,10 +2393,8 @@
       exit('{"etat":"nok","message":"Identifiant non valide"}');
     $r = $resultat->fetch_row();
     $resultat->free();
-    if ( requete('agenda',"DELETE FROM agenda WHERE id = $id",$mysqli) )  {
-      recent($mysqli,5,$id,$r[0]);
+    if ( requete('agenda',"DELETE FROM agenda WHERE id = $id",$mysqli) && recent($mysqli,4,$id) ) 
       exit($_SESSION['message'] = '{"etat":"ok","message":"La suppression a été réalisée."}');
-    }
     exit('{"etat":"nok","message":"L\'événement n\'a pas été supprimé. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 
@@ -2369,7 +2433,7 @@
     // Besoin du nom pour les informations récentes
     $r = $resultat->fetch_row();
     $resultat->free();
-    $type = $r[0];
+    $type = $mysqli->real_escape_string($r[0]);
     if ( $mid )  {
       // Validation de la matière si non nulle
       $resultat = $mysqli->query("SELECT nom FROM matieres WHERE id = $mid");
@@ -2392,7 +2456,7 @@
       $resultat->free();
       // Écriture dans la base de données
       if ( requete('agenda',"UPDATE agenda SET matiere = $mid, type = $tid, debut = '$debut', fin = '$fin', texte = '$texte' WHERE id = $id", $mysqli) )  {
-        recent($mysqli,5,$id,$mid,array('titre'=>"$jour/$mois - $type ".( strlen($matiere) ? $mysqli->real_escape_string("en $matiere ") : '').'(mise à jour)', 'lien'=>"agenda?mois=$annee$mois", 'texte'=>$texte, 'matiere'=>$mid, 'protection'=>0));
+        recent($mysqli,5,$id,array('titre'=>"$jour/$mois - $type ".( strlen($matiere) ? $mysqli->real_escape_string("en $matiere ") : ''), 'lien'=>"agenda?mois=$annee$mois", 'texte'=>$texte, 'matiere'=>$mid));
         $mysqli->query('ALTER TABLE agenda ORDER BY fin, debut');
         exit($_SESSION['message'] = '{"etat":"ok","message":"L\'événement a été modifié."}');
       }
@@ -2401,7 +2465,7 @@
 
     // Nouvel événement
     if ( requete('agenda',"INSERT INTO agenda SET matiere = $mid, type = $tid, debut = '$debut', fin = '$fin', texte = '$texte'", $mysqli) )  {
-      recent($mysqli,5,$mysqli->insert_id,$mid,array('titre'=>"$jour/$mois - $type ".( strlen($matiere) ? $mysqli->real_escape_string("en $matiere ") : ''), 'lien'=>"agenda?mois=$annee$mois", 'texte'=>$texte, 'matiere'=>$mid, 'protection'=>0));
+      recent($mysqli,5,$mysqli->insert_id,array('titre'=>"$jour/$mois - $type ".( strlen($matiere) ? $mysqli->real_escape_string("en $matiere ") : ''), 'lien'=>"agenda?mois=$annee$mois", 'texte'=>$texte, 'matiere'=>$mid, 'protection'=>0));
       $mysqli->query('ALTER TABLE agenda ORDER BY fin, debut');
       exit($_SESSION['message'] = '{"etat":"ok","message":"L\'événement a été ajouté."}');
     }
@@ -2490,7 +2554,7 @@
   if ( requete('agenda',"INSERT INTO agenda (matiere,type,debut,fin,texte) VALUES $insertion", $mysqli) )  {
     $mysqli->query('ALTER TABLE agenda ORDER BY fin, debut');
     $debut = ( strlen($ancien_sql) ) ? $ancien_sql : $nouveau_sql;
-    recent($mysqli,5,$mysqli->insert_id,$matiere,array('titre'=>substr($debut,8,2).'/'.substr($debut,5,2)." - Déplacement de colle en ".$mysqli->real_escape_string("${r[0]}, groupe $groupe"), 'lien'=>'agenda?mois='.substr($debut,2,2).substr($debut,5,2), 'texte'=>$texte, 'matiere'=>$matiere, 'protection'=>0));
+    recent($mysqli,5,$mysqli->insert_id,array('titre'=>substr($debut,8,2).'/'.substr($debut,5,2)." - Déplacement de colle en ".$mysqli->real_escape_string("${r[0]}, groupe $groupe"), 'lien'=>'agenda?mois='.substr($debut,2,2).substr($debut,5,2), 'texte'=>$texte, 'matiere'=>$matiere, 'protection'=>0));
     exit($_SESSION['message'] = '{"etat":"ok","message":"Déplacement de colle ajouté"}');
   }
   else
@@ -2593,24 +2657,25 @@
   // Génération des valeurs de protection
   foreach ( array('colles','cdt','docs') as $fonction )  {
     if ( isset($_REQUEST[$fonction.'_protection']) )  {
-      $val = array_filter($_REQUEST[$fonction.'_protection'],function($id) { return ctype_digit($id); });
-      if ( !count($val) )
+      // Génération de la valeur de protection
+      if ( !count($val = array_filter($_REQUEST[$fonction.'_protection'],function($id) { return ctype_digit($id); })) )
         exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été modifiée. La protection d'accès est incorrecte.\"}");
-      if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-        $protection = $val[0];
-      else  {
-        $protection = 32;
-        foreach (array_slice($val,1) as $v) 
-          $protection = $protection-2**($v-1);
-      }
+      $protection = ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32);
       if ( $protection == $r[$fonction.'_protection'] )
         exit('{"etat":"nok","message":"Aucune action effectuée : la protection saisie est la même que celle déjà en place."}');
-      if ( requete('matieres',"UPDATE matieres SET ${fonction}_protection = $protection WHERE id = $id",$mysqli) )  {
-        if ( $fonction == 'docs' )
-          requete('reps',"UPDATE reps SET protection = $protection WHERE matiere = $id AND parent = 0",$mysqli);
-        exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"La matière <em>${r['nom']}</em> a été modifiée.\"}");
+      if ( !requete('matieres',"UPDATE matieres SET ${fonction}_protection = $protection WHERE id = $id",$mysqli) )
+        exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été modifiée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');        
+      // Mises à jour supplémentaires : répertoire racine, table recents, flux rss
+      if ( $fonction == 'colles' )  {
+        requete('recents',"UPDATE recents SET protection = $protection WHERE type = 2 AND matiere = $id",$mysqli);
+        rss($mysqli, $id, ( $r['colles_protection'] && $protection ) ? $r['colles_protection']^$protection : 0);
+      }
+      elseif ( $fonction == 'docs' )  {
+        requete('reps',"UPDATE reps SET protection = $protection WHERE matiere = $id AND parent = 0",$mysqli);
+        requete('recents',"UPDATE recents SET protection = $protection WHERE type = 3 AND matiere = $id",$mysqli);
+        rss($mysqli, $id, ( $r['docs_protection'] && $protection ) ? $r['docs_protection']^$protection : 0);
       }
-      exit("{\"etat\":\"nok\",\"message\":\"La matière <em>${r['nom']}</em> n'a pas été modifiée. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'»."}');        
+      exit($_SESSION['message'] = "{\"etat\":\"ok\",\"message\":\"La matière <em>${r['nom']}</em> a été modifiée.\"}");
     }
   }
 }
@@ -2620,26 +2685,43 @@
 ///////////////////////////////////////////
 elseif ( $action == 'prefsglobales' )  {
 
-  // Préférences de l'agenda : protection globale et nombre d'événements sur 
-  // la page d'accueil
-  if ( isset($_REQUEST['protection_agenda']) && isset($_REQUEST['nb_agenda_index']) && count( $val = array_filter($_REQUEST['protection_agenda'],function($id) { return ctype_digit($id); }) ) && ctype_digit($nb_agenda_index = $_REQUEST['nb_agenda_index']) )  {
-    if ( ( $val[0] == 0 ) || ( $val[0] == 32 ) )
-      $protection = $val[0];
-    else  {
-      $protection = 32;
-      foreach (array_slice($val,1) as $v) 
-        $protection = $protection-2**($v-1);
-    }
-    if ( requete('prefs',"UPDATE prefs SET val = $protection WHERE nom='protection_agenda'",$mysqli) && requete('prefs',"UPDATE prefs SET val = $nb_agenda_index WHERE nom='nb_agenda_index'",$mysqli) )
+  // Préférences de l'agenda : protection globale et nombre d'événements sur la page d'accueil
+  if ( isset($_REQUEST['protection_agenda']) && isset($_REQUEST['nb_agenda_index']) && ctype_digit($nb_agenda_index = $_REQUEST['nb_agenda_index']) )  {
+    // Génération de la valeur de protection
+    if ( !count($val = array_filter($_REQUEST['protection_agenda'],function($id) { return ctype_digit($id); })) )
+      exit($_SESSION['message'] = '{"etat":"nok","message":"Les préférences d\'accès à l\'agenda n\'ont pas été modifiées."}');
+    $protection = ( ( $val[0] == 0 ) || ( $val[0] == 32 ) ) ? $val[0] : array_reduce($val, function($s,$v) { return $s - ( ( $v<6 ) ? 1<<($v-1) : 0 ); }, 32);
+    if ( requete('prefs',"UPDATE prefs SET val = $protection WHERE nom='protection_agenda'",$mysqli)
+      && requete('prefs',"UPDATE prefs SET val = $nb_agenda_index WHERE nom='nb_agenda_index'",$mysqli) )
       exit($_SESSION['message'] = '{"etat":"ok","message":"Les préférences de l\'agenda ont été modifiées."}');
     exit('{"etat":"nok","message":"Les préférences globales de l\'agenda n\'ont pas été modifiées. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
   
+  // Préférence d'envoi de mail, venant de utilisateurs-mails.php
+  // $depuis : numéro du groupe expéditeur traité
+  // $vers : numéro du groupe destinataire traité ou 0 pour les traiter tous
+  // $ok : 1 pour autoriser, 0 pour interdire
+  elseif ( isset($_REQUEST['mails']) && isset($_REQUEST['depuis']) && isset($_REQUEST['vers']) && isset($_REQUEST['val']) && in_array($depuis = $_REQUEST['depuis'], array(2,3,4,5)) && in_array($vers = $_REQUEST['vers'], array(0,2,3,4,5)) && ctype_digit($ok = $_REQUEST['val']) )  {
+    // Masque : bits à modifier
+    $masque = ( $vers ) ? 1 << 4*($depuis-2)+$vers-2 : 15 << 4*($depuis-2);
+    // Récupération de la valeur originale
+    $resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+    $val_orig = $resultat->fetch_row()[0];
+    // Modification
+    $val = ( $ok ) ? $val_orig | $masque : $val_orig & ( 65535 - $masque );
+    if ( $val == $val_orig )
+      exit('{"etat":"nok","message":"Aucune action effectuée : les autorisations d\'envoi demandées sont déjà celles en place."}');
+    if ( requete('prefs',"UPDATE prefs SET val = $val WHERE nom='autorisation_mails'",$mysqli) )
+      exit($_SESSION['message'] = '{"etat":"ok","message":"Les autorisations d\'envoi de courriels ont été modifiées."}');
+    exit('{"etat":"nok","message":"Les autorisations d\'envoi de courriels n\'ont pas été modifiées. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+  }
+  
   // Préférence de création de compte, venant de utilisateurs.php
-  if ( isset($_REQUEST['creation_compte']) )  {
-    if ( requete('prefs','UPDATE prefs SET val = '.intval(isset($_REQUEST['autoriser'])).' WHERE nom="creation_compte"',$mysqli) )
-      exit($_SESSION['message'] = '{"etat":"ok","message":"Les créations de compte ont été '.( intval(isset($_REQUEST['autoriser'])) ? 'autorisées' : 'interdites' ).'."}');
-    exit('{"etat":"nok","message":"Les préférences globales de l\'agenda n\'ont pas été modifiées. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
+  elseif ( isset($_REQUEST['creation_compte']) )  {
+    $val = intval(isset($_REQUEST['autoriser']));
+    if ( requete('prefs',"UPDATE prefs SET val = $val WHERE nom='creation_compte'",$mysqli) )
+      exit($_SESSION['message'] = '{"etat":"ok","message":"Les créations de compte ont été '.( $val ? 'autorisées' : 'interdites' ).'."}');
+    exit('{"etat":"nok","message":"La possibilité de création de comptes n\'a pas été modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'»."}');
   }
 }
 
diff -urN cahier-de-prepa8.1.1/cdt.php cahier-de-prepa9.0.0/cdt.php
--- cahier-de-prepa8.1.1/cdt.php	2018-10-19 00:21:49.070458665 +0200
+++ cahier-de-prepa9.0.0/cdt.php	2019-08-28 01:48:23.005059192 +0200
@@ -64,28 +64,14 @@
 //////////////////////////////////////////////////////
 
 // Récupération des semaines et du nombre de semaines
-$resultat = $mysqli->query("SELECT id, DATE_FORMAT(debut,'%w%Y%m%e') AS debut, DATE_FORMAT(debut,'%y%v') AS semaine, vacances FROM semaines");
+$resultat = $mysqli->query("SELECT semaines.id, DATE_FORMAT(debut,'%w%Y%m%e') AS debut, DATE_FORMAT(debut,'%y%v') AS semaine, nom AS vacances 
+                            FROM semaines LEFT JOIN vacances ON semaines.vacances = vacances.id ORDER BY semaines.id");
 $select_semaines = "\n      <option value=\"0\">Toute l'année</option>";
 $semaines = $semaines_id = array(0=>'');
 while ( $r = $resultat->fetch_assoc() )  {
   $semaines[] = $r;
   $semaines_id[] = $r['semaine'];
-  switch ( $r['vacances'] )  {
-    case 0:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">".format_date($r['debut']).'</option>';
-      break;
-    case 1:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances de Toussaint</option>";
-      break;
-    case 2:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances de Noël</option>";
-      break;
-    case 3:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances d'hiver</option>";
-      break;
-    case 4:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances de Pâques</option>";
-  }
+  $select_semaines .= "\n      <option value=\"${r['id']}\">".( $r['vacances'] ?: format_date($r['debut']) ).'</option>';
 }
 $resultat->free();
 $nmax = count($semaines);
@@ -161,27 +147,11 @@
     </select>
     <select id=\"semaines\" onchange=\"window.location='?$cle&amp;n='+this.value+'&amp;seances='+$(this).prev().val();\">$select_semaines
     </select>
-    <input type=\"text\" value=\"$recherche\" onchange=\"window.location='?$cle&amp;recherche='+this.value;\" title=\"Recherche dans les textes des programmes de colles\">
     <span class=\"icon-recherche\" onclick=\"if ( !$(this).prev().is(':visible')) $(this).prev().show(); else window.location='?$cle&amp;recherche='+$(this).prev().val();\"></span>
+    <input type=\"text\" value=\"$recherche\" onchange=\"window.location='?$cle&amp;recherche='+this.value;\" title=\"Recherche dans les textes des programmes de colles\">
   </p>
 ";
 
-// Affichage du titre de chaque semaine
-function generetitre($date,$vacances)  {
-  switch ( $vacances )  {
-    case 0:
-      return'Semaine du '.format_date($date);
-    case 1:
-      return ucfirst(format_date($date))."&nbsp;: Vacances de Toussaint";
-    case 2:
-      return ucfirst(format_date($date))."&nbsp;: Vacances de Noël";
-    case 3:
-      return ucfirst(format_date($date))."&nbsp;: Vacances d'hiver";
-    case 4:
-      return ucfirst(format_date($date))."&nbsp;: Vacances de Pâques";
-  }
-}
-
 // Affichage public sans édition
 if ( !$edition )  {
   echo $boutons;
@@ -206,8 +176,8 @@
           $semaine = $semaine+1;
           if ( $semaine == $r['semaine'] )
             $compteur = $compteur+1;
-          if ( !strlen($recherche) || ( $semaine == $r['semaine'] ) )
-            echo "\n  <h3>".generetitre($semaines[$semaine]['debut'],$semaines[$semaine]['vacances']).'</h3>';
+          if ( !$recherche || ( $semaine == $r['semaine'] ) )
+            echo "\n  <h3>".( ( $v = $semaines[$semaine]['vacances'] ) ? ucfirst(format_date($semaines[$semaine]['debut']))."&nbsp;: $v" : 'Semaine du '.format_date($semaines[$semaine]['debut']) ).'</h3>';
         }
         // Élément du cahier de texte
         $mathjax = $mathjax ?: boolval(strpos($r['texte'],'$')+strpos($r['texte'],'\\'));
@@ -270,8 +240,8 @@
           $semaine = $semaine+1;
           if ( $semaine == $r['semaine'] )
             $compteur = $compteur+1;
-          if ( !strlen($recherche) || ( $semaine == $r['semaine'] ) )
-            echo "\n  <h3>".generetitre($semaines[$semaine]['debut'],$semaines[$semaine]['vacances']).'</h3>';
+          if ( !$recherche || ( $semaine == $r['semaine'] ) )
+            echo "\n  <h3>".( ( $v = $semaines[$semaine]['vacances'] ) ? ucfirst(format_date($semaines[$semaine]['debut']))."&nbsp;: $v" : 'Semaine du '.format_date($semaines[$semaine]['debut']) ).'</h3>';
         }
         // Élément du cahier de texte
         $mathjax = $mathjax ?: boolval(strpos($r['texte'],'$')+strpos($r['texte'],'\\'));
@@ -343,7 +313,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Administratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Fonction désactivée</option>';
   $p = $matiere['protection'];
diff -urN cahier-de-prepa8.1.1/CHANGELOG.php cahier-de-prepa9.0.0/CHANGELOG.php
--- cahier-de-prepa8.1.1/CHANGELOG.php	2018-11-11 00:57:39.075674052 +0100
+++ cahier-de-prepa9.0.0/CHANGELOG.php	2019-08-29 04:09:15.893212925 +0200
@@ -1,4 +1,4 @@
-Version actuelle : 8.1.1 (11/11/18)
+Version actuelle : 9.0.0 (29/08/19)
 ===================
 Changements :
 1.0   31/08/11 Première version
@@ -204,7 +204,7 @@
     des mails, réglage particulier à chaque compte
   * Gestion des accès entièrement revue, possibilité de réglage beaucoup plus fin
     pour la protection de l'accès de chaque ressource 
-  * Création d'un nouveau type d'utilisateur : administration
+  * Création d'un nouveau type d'utilisateur : administration du lycée
   * Gestion des utilisateurs améliorée
     * Validations/suppressions/modifications multiples d'utilisateurs
     * Possibilité de "désactiver" un compte sans le supprimer, par exemple pour
@@ -224,27 +224,41 @@
   * Possibilité d'impression du relevé de colles pour le compte administratif
   * Possibilité de déclaration de séances de cours ou TD sans note 
 8.1.1 11/11/18 Correction de bugs
+9.0.0 29/08/19 Nouvelles fonctionnalités :
+  * Interface globale de connexion permettant une meilleure expérience des 
+    utilisateurs de plusieurs Cahiers, et changement de Cahier en direct
+  * Connexion possible à l'aide de son adresse électronique ou de l'identifiant
+  * Nouvelle interface sur écran mobile et correction de bugs d'affichage
+  * Nouvelle gestion de l'autorisation de l'envoi de courriel, plus lisible,
+    par groupe d'utilisateurs.
+  * Mise en avant des nouveaux contenus sur une page spéciale
+  * Deux dates enregistrables pour les informations, programmes de colle,
+    documents : date de première publication, date de mise à jour
+  * Correction de bugs pouvant amener des incohérences après des modifications
+    ou suppressions massives.
+  * Demande de confirmation si un texte a été saisi sans être enregistré (mais
+    dépend du réglage du navigateur)
+  * Planning dépendant de la zone scolaire
 
 ===================
 
 Todo :
 
-[8.2] Janvier 2019
-  * Mode lecture
-  * Page de préférences globales : création de compte, protection globale, titre
-  * Page de statistiques des colles toutes matières confondues ?
-  * Correction des mises à jour multiples vers les informations récentes
-  * FAQ
+[ 9.1 ] Septembre 2019
+  * Comptes administrateurs non nécessairement professeurs et inversement
+  * Possibilité pour les administrateurs de laisser un message sur une page ?
+  * Amélioration de la gestion des notes : page unique d'accès pour les élèves 
+    et les colleurs, vue simplifiée pour les élèves, ajout de commentaires
+  * Amélioration de l'agenda
+
+[ 9.2 ] Janvier 2019
+  * Système de récupération des données et des documents
+
+[ 10.0 ] Août 2020
   * Affichage en ligne des vidéos et fichiers sonores
   * Pièce jointe sur les mails : téléchargement, enregistrement dans un répertoire
   hors d'atteinte, lien spécial à insérer dans le corps du mail.
-  * À côté de Cahier de Prépa : une interface spéciale pour l'administration des
-  lycées qui voudraient récupérer les notes de colles sur plusieurs classes.
-
-[ 9.0 ] Septembre 2019
-  * Commentaires sur les notes de colles
-  * Harmonisation des matières : listes de matières pour les filières classiques.
-  * Notes de colles : pouvoir préremplir de façon toujours identique
+  * Mode lecture, mode « vision en tant que » pour les administrateurs
   * Meilleure visiblité des protections dans le menu
   * Réglages des fichiers xls téléchargés (notes & utilisateurs)
   * Mise en place d'un système de forum ?
@@ -256,28 +270,27 @@
     * Vue de l'agenda sous forme de liste d'événements
     * Recherche dans les événements
   * Raccourcis cdt : texte pré-défini
-  * Système de récupération des données/documents
   * Paramétrage des styles pour les titres, des couleurs
-  * Renvoi d'invitation
-
 
 =======
 
 Autres remarques / propositions :
+  * Renvoi d'invitation
+  * Notes de colles : pouvoir préremplir de façon toujours identique
+  * Page de statistiques des colles toutes matières confondues ?
+  * FAQ
+  * Page de préférences globales : création de compte, protection globale, titre
+  * Harmonisation des matières : listes de matières pour les filières classiques.
   * Envoi multiple de documents
-  * Modifications multiples sur des éléments (informations, pages, types ou
-    séances de cahier de texte, documents...)
+  * Interface : glisser-déplacer pour changer les ordres d'affichage
   * Tags dans les cahiers de texte
   * Programme de colles par quinzaine
   * ajouter la durée des séances dans le cahier de texte
   * bug : interdire les "." dans les clés
   * matière éditable depuis le menu -> modification de la matière seule (matieres.php accessible avec une clé)
   * notes : savoir combien de notes sont attribuées à un compte avant suppression (gestion des doublons)
-  * news : date de création, date de mise à jour ?
   * modification de docs par les élèves
   * modification d'items de l'agenda par les élèves
-  * ajout de la possibilité d'envoi de notification à chaque saisie de document/information/programme de colle
-  * prévention javascript de changement de page/fermeture de sous-fenêtre, en cours d'édition
-  * mise en évidence (surlignage) des champs modifiés, envoi sélectif ?
   * correction : détection de la touche entrée sur les input/select plus globale (supprimer les copies multiples)
   * correction : utiliser le data-matiere associé à body dans les actions ajax
+  * interne : séparer ajax.php/ajaxadmin.php, séparer 
diff -urN cahier-de-prepa8.1.1/colles.php cahier-de-prepa9.0.0/colles.php
--- cahier-de-prepa8.1.1/colles.php	2018-10-15 17:50:45.624901382 +0200
+++ cahier-de-prepa9.0.0/colles.php	2019-08-28 03:35:18.257231642 +0200
@@ -54,27 +54,13 @@
 //////////////////////////////////////////////////////////////////
 
 // Récupération des semaines et du nombre de semaines
-$resultat = $mysqli->query("SELECT id, DATE_FORMAT(debut,'%w%Y%m%e') AS debut, DATE_FORMAT(debut,'%y%v') AS semaine, vacances FROM semaines");
+$resultat = $mysqli->query("SELECT semaines.id, DATE_FORMAT(debut,'%w%Y%m%e') AS debut, DATE_FORMAT(debut,'%y%v') AS semaine, nom AS vacances 
+                            FROM semaines LEFT JOIN vacances ON semaines.vacances = vacances.id ORDER BY semaines.id");
 $select_semaines = "\n      <option value=\"0\">Toute l'année</option>";
 $semaines = array(0=>'');
 while ( $r = $resultat->fetch_assoc() )  {
   $semaines[] = $r['semaine'];
-  switch ( $r['vacances'] )  {
-    case 0:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">".format_date($r['debut']).'</option>';
-      break;
-    case 1:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances de Toussaint</option>";
-      break;
-    case 2:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances de Noël</option>";
-      break;
-    case 3:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances d'hiver</option>";
-      break;
-    case 4:
-      $select_semaines .= "\n      <option value=\"${r['id']}\">Vacances de Pâques</option>";
-  }
+  $select_semaines .= "\n      <option value=\"${r['id']}\">".( $r['vacances'] ?: format_date($r['debut']) ).'</option>';
 }
 $resultat->free();
 $nmax = count($semaines);
@@ -124,8 +110,8 @@
     <a class=\"icon-voirtout\" href=\"?${matiere['cle']}&amp;tout\" title=\"Voir l'ensemble du programme de colles\"></a>
     <select id=\"semaines\" onchange=\"window.location='?${matiere['cle']}&amp;'+((this.value>0)?'n='+this.value:'tout');\">$select_semaines
     </select>
-    <input type=\"text\" value=\"$recherche\" onchange=\"window.location='?${matiere['cle']}&amp;recherche='+this.value;\" title=\"Recherche dans les textes des programmes de colles\">
     <span class=\"icon-recherche\" onclick=\"if( $(this).prev().is(':visible') && $(this).prev().val().length ) window.location='?${matiere['cle']}&amp;recherche='+$(this).prev().val(); else $(this).prev().show();\"></span>
+    <input type=\"text\" value=\"$recherche\" onchange=\"window.location='?${matiere['cle']}&amp;recherche='+this.value;\" title=\"Recherche dans les textes des programmes de colles\">
   </p>
 ";
 
@@ -150,21 +136,21 @@
   echo $boutons;
   if ( $n !== false )  {
     // Affichage des programmes de colles diffusés
-    if ( strlen($recherche) > 0 )
-      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, s.vacances, c.texte
-                                  FROM colles AS c LEFT JOIN semaines AS s ON c.semaine=s.id
+    if ( $recherche )
+      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, nom AS vacances, c.texte
+                                  FROM colles AS c LEFT JOIN semaines AS s ON c.semaine=s.id LEFT JOIN vacances ON s.vacances = vacances.id
                                   WHERE c.matiere = $mid AND c.cache = 0 AND c.texte LIKE '%".$mysqli->real_escape_string($_REQUEST['recherche']).'%\' ORDER BY c.semaine');
     else
-      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, s.vacances, c.texte
-                                  FROM semaines AS s
+      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, nom AS vacances, c.texte
+                                  FROM semaines AS s LEFT JOIN vacances ON s.vacances = vacances.id
                                   LEFT JOIN (SELECT texte, semaine FROM colles WHERE matiere = $mid AND cache = 0) AS c ON c.semaine=s.id
-                                  $requete" );
+                                  $requete ORDER BY s.id" );
     $mysqli->close();
     if ( $resultat->num_rows > 0 )  {
       $compteur = 0;
       while ( ( $compteur < $nb ) && ( $r = $resultat->fetch_assoc() ) )  {
         $mathjax = $mathjax ?: boolval(strpos($r['texte'],'$')+strpos($r['texte'],'\\'));
-        $titre = generetitre($r['debut'],$r['vacances']);
+        $titre = ( $r['vacances'] ) ? ucfirst(format_date($r['debut']))."&nbsp;: ${r['vacances']}" : 'Semaine du '.format_date($r['debut']);
         if ( $r['colle'] )  {
           $compteur = $compteur+1;
           $texte = $r['texte'] ?: '    <p>Le programme de colles de cette semaine n\'est pas défini.</p>';
@@ -205,12 +191,12 @@
     // identifiant propre pour assurer une cohérence entre les programmes saisis
     // et ceux non saisis/supprimés.
     if ( strlen($recherche) )
-      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, s.vacances, c.texte, s.id, c.cache 
-                                  FROM colles AS c LEFT JOIN semaines AS s ON c.semaine=s.id
+      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, nom AS vacances, c.texte, s.id, c.cache 
+                                  FROM colles AS c LEFT JOIN semaines AS s ON c.semaine=s.id LEFT JOIN vacances ON s.vacances = vacances.id
                                   WHERE c.matiere = $mid AND c.texte LIKE '%$recherche%' ORDER BY c.semaine");
     else
-      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, s.vacances, c.texte, s.id, c.cache 
-                                  FROM semaines AS s
+      $resultat = $mysqli->query("SELECT DATE_FORMAT(s.debut,'%w%Y%m%e') AS debut, s.colle, nom AS vacances, c.texte, s.id, c.cache 
+                                  FROM semaines AS s LEFT JOIN vacances ON s.vacances = vacances.id
                                   LEFT JOIN (SELECT texte, semaine, cache FROM colles WHERE matiere = $mid) AS c ON c.semaine=s.id
                                   $requete");
     $mysqli->close();
@@ -218,7 +204,7 @@
       $compteur = 0;
       while ( ( $compteur < $nb ) && ( $r = $resultat->fetch_assoc() ) )  {
         $mathjax = $mathjax ?: boolval(strpos($r['texte'],'$')+strpos($r['texte'],'\\'));
-        $titre = generetitre($r['debut'],$r['vacances']);
+        $titre = ( $r['vacances'] ) ? ucfirst(format_date($r['debut']))."&nbsp;: ${r['vacances']}" : 'Semaine du '.format_date($r['debut']);
         if ( $r['colle'] )  {
           $compteur = $compteur+1;
           if ( is_null($r['texte']) )
@@ -242,7 +228,7 @@
     <a class="icon-aide" title="Aide pour l'édition de ce programme de colles"></a>
     $bouton_cache
     <a class="icon-supprime" title="Supprimer ce programme de colles"></a>
-    <div class="editable edithtml" data-id="colles|texte|${r['id']}-$mid" placeholder="Texte du programme de colles">
+    <div class="editable edithtml majpubli" data-id="colles|texte|${r['id']}-$mid" placeholder="Texte du programme de colles">
 ${r['texte']}
     </div>
   </article>
@@ -277,7 +263,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Administratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Fonction désactivée</option>';
   $p = $matiere['protection'];
diff -urN cahier-de-prepa8.1.1/config.php cahier-de-prepa9.0.0/config.php
--- cahier-de-prepa8.1.1/config.php	2019-08-29 00:49:32.411253771 +0200
+++ cahier-de-prepa9.0.0/config.php	2019-08-11 15:00:48.336183323 +0200
@@ -2,8 +2,10 @@
 // Fichier de configuration de Cahier de Prépa
 
 // Adresse web
-// Ne pas mettre le protocole ("https://") ni de "/" final
-$site = 'cahier-de-prepa.fr/ts-langevin';
+// Domaine : le nom de domaine (pas de "https://" ni de "/" final)
+// Chemin : la suite de l'adresse, commençant et finissant par "/"
+$domaine = '';
+$chemin = '';
 
 // Accès à la base de données MySQL
 /* $serveur est le nom du serveur. localhost est la valeur par défaut.
@@ -26,4 +28,10 @@
 // Les adresses réelles des expéditeurs sont utilisées si vide
 $mailenvoi = 'ne-pas-repondre@cahier-de-prepa.fr';
 
+// Interface globale
+// Si l'interface globale est présente, on l'indique avec le chemin relatif du
+// répertoire où elle se trouve (avec slash final).
+// Laisser la chaîne vide ou égale à false désactive la fonctionnalité.
+$interfaceglobale = false;
+
 ?>
diff -urN cahier-de-prepa8.1.1/css/icones.css cahier-de-prepa9.0.0/css/icones.css
--- cahier-de-prepa8.1.1/css/icones.css	2018-10-27 22:33:15.519945682 +0200
+++ cahier-de-prepa9.0.0/css/icones.css	2019-08-25 18:11:52.452375669 +0200
@@ -1,10 +1,6 @@
 @font-face {
   font-family: 'icomoon';
-  src:url('../fonts/icomoon.eot?18');
-  src:url('../fonts/icomoon.eot?#iefix18') format('embedded-opentype'),
-    url('../fonts/icomoon.ttf?18') format('truetype'),
-    url('../fonts/icomoon.woff?18') format('woff'),
-    url('../fonts/icomoon.svg?18#icomoon') format('svg');
+  src:url('../fonts/icomoon.woff?24') format('woff');
   font-weight: normal;
   font-style: normal;
 }
@@ -35,6 +31,7 @@
     color: #777;
     margin-right: -0.5em;
 }
+
 .icon-montre:before {
   content: "\e600";
 }
@@ -53,7 +50,7 @@
 .icon-annule:before {
   content: "\e605";
 }
-.icon-ok:before, .icon-envoidoc:before  {
+.icon-ok:before, .icon-envoidoc:before {
   content: "\e606";
 }
 .icon-prefs:before {
@@ -142,7 +139,6 @@
 }
 .icon-voirtout:before {
   content: "\e623";
-  color: #000;
 }
 .icon-accueil:before {
   content: "\e624";
@@ -225,80 +221,96 @@
 .icon-doc-mp4:before {
   content: "\e63e";
 }
-.icon-doc-pyt:before {
+.icon-doc-py:before {
   content: "\e63f";
 }
-.icon-rss:before {
+.icon-doc-sql:before {
   content: "\e640";
 }
-.icon-infos:before {
+.icon-doc-db:before {
   content: "\e641";
 }
-.icon-colles:before {
+.icon-recent:before {
   content: "\e642";
 }
-.icon-recent:before {
+.icon-rss:before {
   content: "\e643";
 }
-.icon-lock1:before {
+.icon-infos:before {
   content: "\e644";
 }
-.icon-lock2:before {
+.icon-colles:before {
   content: "\e645";
 }
-.icon-lock3:before {
+.icon-lock1:before {
   content: "\e646";
 }
-.icon-lock4:before {
+.icon-lock2:before {
   content: "\e647";
 }
-.icon-lock5:before {
+.icon-lock3:before {
   content: "\e648";
 }
-.icon-agenda:before {
+.icon-lock4:before {
   content: "\e649";
 }
-.icon-ajout-colle:before {
+.icon-lock5:before {
   content: "\e64a";
 }
-.icon-messages:before {
+.icon-agenda:before {
   content: "\e64b";
 }
-.icon-lock:before {
+.icon-ajout-colle:before {
   content: "\e64c";
 }
-.icon-locktotal:before {
+.icon-messages:before {
   content: "\e64d";
 }
-.icon-editemultiple:before {
+.icon-lock:before {
   content: "\e64e";
 }
-.icon-plie:before {
+.icon-locktotal:before {
   content: "\e64f";
 }
-.icon-deplie:before {
+.icon-editemultiple:before {
   content: "\e650";
 }
-.icon-mailenvoi:before {
+.icon-plie:before {
   content: "\e651";
 }
-.icon-nok:before {
+.icon-deplie:before {
   content: "\e652";
 }
-.icon-active:before {
+.icon-mailenvoi:before {
   content: "\e653";
 }
-.icon-desactive:before {
+.icon-nok:before {
   content: "\e654";
 }
-.icon-supprutilisateur:before {
+.icon-active:before {
   content: "\e655";
 }
-.icon-validutilisateur:before {
+.icon-desactive:before {
   content: "\e656";
 }
-.icon-lecture:before {
+.icon-supprutilisateur:before {
   content: "\e657";
 }
-.icon-nolecture:before {
+.icon-valideutilisateur:before {
   content: "\e658";
+}
+.icon-lecture:before {
+  content: "\e659";
+}
+.icon-nolecture:before {
+  content: "\e65a";
+}
+.icon-echange:before {
+  content: "\e65b";
+}
+.icon-notes:before {
+  content: "\e65c";
+}
+.icon-cdt:before {
+  content: "\e65d";
+}
diff -urN cahier-de-prepa8.1.1/css/icones.min.css cahier-de-prepa9.0.0/css/icones.min.css
--- cahier-de-prepa8.1.1/css/icones.min.css	2018-10-31 03:52:49.115198187 +0100
+++ cahier-de-prepa9.0.0/css/icones.min.css	2019-08-28 19:37:25.357431181 +0200
@@ -1 +1 @@
-@font-face{font-family:'icomoon';src:url('../fonts/icomoon.eot?18');src:url('../fonts/icomoon.eot?#iefix18') format('embedded-opentype'),url('../fonts/icomoon.ttf?18') format('truetype'),url('../fonts/icomoon.woff?18') format('woff'),url('../fonts/icomoon.svg?18#icomoon') format('svg');font-weight:normal;font-style:normal}[class^="icon-"]{font-family:'icomoon'!important;color:black;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a[class^="icon-"]{cursor:pointer;text-decoration:none}span.icon-minilock{position:relative!important;left:-0.3em;top:.1em;color:#777;margin-right:-0.5em}.icon-montre:before{content:"\e600"}.icon-cache:before{content:"\e601"}.icon-aide:before{content:"\e602"}.icon-ajoute:before,.icon-ajoutecolle:before{content:"\e603"}.icon-supprime:before{content:"\e604"}.icon-annule:before{content:"\e605"}.icon-ok:before,.icon-envoidoc:before{content:"\e606"}.icon-prefs:before{content:"\e607"}.icon-monte:before{content:"\e608"}.icon-descend:before{content:"\e609"}.icon-ferme:before{content:"\e60a"}.icon-epingle:before{content:"\e60b"}.icon-par1:before{content:"\e60c"}.icon-par2:before{content:"\e60d"}.icon-par3:before{content:"\e60e"}.icon-gras:before{content:"\e60f"}.icon-italique:before{content:"\e610"}.icon-souligne:before{content:"\e611"}.icon-omega:before{content:"\e612"}.icon-sigma:before{content:"\e613"}.icon-exp:before{content:"\e614"}.icon-ind:before{content:"\e615"}.icon-ol:before{content:"\e616"}.icon-ul:before{content:"\e617"}.icon-lien1:before{content:"\e618"}.icon-lien2:before{content:"\e619"}.icon-retour:before{content:"\e61a"}.icon-source:before{content:"\e61b"}.icon-nosource:before{content:"\e61c"}.icon-tex:before{content:"\e61d"}.icon-titres:before{content:"\e61e"}.icon-edite:before,.icon-editedoc:before,.icon-editerep:before{content:"\e61f"}.icon-precedent:before{content:"\e620"}.icon-suivant:before{content:"\e621"}.icon-recherche:before{content:"\e622"}.icon-voirtout:before{content:"\e623";color:#000}.icon-accueil:before{content:"\e624"}.icon-imprime:before{content:"\e625"}.icon-connexion:before{content:"\e626"}.icon-deconnexion:before{content:"\e627"}.icon-mail:before{content:"\e628"}.icon-menu:before{content:"\e629"}.icon-cocher:before{content:"\e62a"}.icon-decocher:before{content:"\e62b"}.icon-rep:before{content:"\e62c"}.icon-rep-open:before{content:"\e62d"}.icon-download:before{content:"\e62e"}.icon-minilock:before{content:"\e62f"}.icon-alphaasc:before{content:"\e630"}.icon-alphadesc:before{content:"\e631"}.icon-chronoasc:before{content:"\e632"}.icon-chronodesc:before{content:"\e633"}.icon-ajouterep:before{content:"\e634"}.icon-ajoutedoc:before{content:"\e635"}.icon-doc:before{content:"\e636"}.icon-doc-pdf:before{content:"\e637"}.icon-doc-doc:before{content:"\e638"}.icon-doc-xls:before{content:"\e639"}.icon-doc-ppt:before{content:"\e63a"}.icon-doc-jpg:before{content:"\e63b"}.icon-doc-zip:before{content:"\e63c"}.icon-doc-mp3:before{content:"\e63d"}.icon-doc-mp4:before{content:"\e63e"}.icon-doc-pyt:before{content:"\e63f"}.icon-rss:before{content:"\e640"}.icon-infos:before{content:"\e641"}.icon-colles:before{content:"\e642"}.icon-recent:before{content:"\e643"}.icon-lock1:before{content:"\e644"}.icon-lock2:before{content:"\e645"}.icon-lock3:before{content:"\e646"}.icon-lock4:before{content:"\e647"}.icon-lock5:before{content:"\e648"}.icon-agenda:before{content:"\e649"}.icon-ajout-colle:before{content:"\e64a"}.icon-messages:before{content:"\e64b"}.icon-lock:before{content:"\e64c"}.icon-locktotal:before{content:"\e64d"}.icon-editemultiple:before{content:"\e64e"}.icon-plie:before{content:"\e64f"}.icon-deplie:before{content:"\e650"}.icon-mailenvoi:before{content:"\e651"}.icon-nok:before{content:"\e652"}.icon-active:before{content:"\e653"}.icon-desactive:before{content:"\e654"}.icon-supprutilisateur:before{content:"\e655"}.icon-validutilisateur:before{content:"\e656"}.icon-lecture:before{content:"\e657"}.icon-nolecture:before{content:"\e658";
\ No newline at end of file
+@font-face{font-family:'icomoon';src:url('../fonts/icomoon.woff?24') format('woff');font-weight:normal;font-style:normal}[class^="icon-"]{font-family:'icomoon'!important;color:black;speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}a[class^="icon-"]{cursor:pointer;text-decoration:none}span.icon-minilock{position:relative!important;left:-0.3em;top:.1em;color:#777;margin-right:-0.5em}.icon-montre:before{content:"\e600"}.icon-cache:before{content:"\e601"}.icon-aide:before{content:"\e602"}.icon-ajoute:before,.icon-ajoutecolle:before{content:"\e603"}.icon-supprime:before{content:"\e604"}.icon-annule:before{content:"\e605"}.icon-ok:before,.icon-envoidoc:before{content:"\e606"}.icon-prefs:before{content:"\e607"}.icon-monte:before{content:"\e608"}.icon-descend:before{content:"\e609"}.icon-ferme:before{content:"\e60a"}.icon-epingle:before{content:"\e60b"}.icon-par1:before{content:"\e60c"}.icon-par2:before{content:"\e60d"}.icon-par3:before{content:"\e60e"}.icon-gras:before{content:"\e60f"}.icon-italique:before{content:"\e610"}.icon-souligne:before{content:"\e611"}.icon-omega:before{content:"\e612"}.icon-sigma:before{content:"\e613"}.icon-exp:before{content:"\e614"}.icon-ind:before{content:"\e615"}.icon-ol:before{content:"\e616"}.icon-ul:before{content:"\e617"}.icon-lien1:before{content:"\e618"}.icon-lien2:before{content:"\e619"}.icon-retour:before{content:"\e61a"}.icon-source:before{content:"\e61b"}.icon-nosource:before{content:"\e61c"}.icon-tex:before{content:"\e61d"}.icon-titres:before{content:"\e61e"}.icon-edite:before,.icon-editedoc:before,.icon-editerep:before{content:"\e61f"}.icon-precedent:before{content:"\e620"}.icon-suivant:before{content:"\e621"}.icon-recherche:before{content:"\e622"}.icon-voirtout:before{content:"\e623"}.icon-accueil:before{content:"\e624"}.icon-imprime:before{content:"\e625"}.icon-connexion:before{content:"\e626"}.icon-deconnexion:before{content:"\e627"}.icon-mail:before{content:"\e628"}.icon-menu:before{content:"\e629"}.icon-cocher:before{content:"\e62a"}.icon-decocher:before{content:"\e62b"}.icon-rep:before{content:"\e62c"}.icon-rep-open:before{content:"\e62d"}.icon-download:before{content:"\e62e"}.icon-minilock:before{content:"\e62f"}.icon-alphaasc:before{content:"\e630"}.icon-alphadesc:before{content:"\e631"}.icon-chronoasc:before{content:"\e632"}.icon-chronodesc:before{content:"\e633"}.icon-ajouterep:before{content:"\e634"}.icon-ajoutedoc:before{content:"\e635"}.icon-doc:before{content:"\e636"}.icon-doc-pdf:before{content:"\e637"}.icon-doc-doc:before{content:"\e638"}.icon-doc-xls:before{content:"\e639"}.icon-doc-ppt:before{content:"\e63a"}.icon-doc-jpg:before{content:"\e63b"}.icon-doc-zip:before{content:"\e63c"}.icon-doc-mp3:before{content:"\e63d"}.icon-doc-mp4:before{content:"\e63e"}.icon-doc-py:before{content:"\e63f"}.icon-doc-sql:before{content:"\e640"}.icon-doc-db:before{content:"\e641"}.icon-recent:before{content:"\e642"}.icon-rss:before{content:"\e643"}.icon-infos:before{content:"\e644"}.icon-colles:before{content:"\e645"}.icon-lock1:before{content:"\e646"}.icon-lock2:before{content:"\e647"}.icon-lock3:before{content:"\e648"}.icon-lock4:before{content:"\e649"}.icon-lock5:before{content:"\e64a"}.icon-agenda:before{content:"\e64b"}.icon-ajout-colle:before{content:"\e64c"}.icon-messages:before{content:"\e64d"}.icon-lock:before{content:"\e64e"}.icon-locktotal:before{content:"\e64f"}.icon-editemultiple:before{content:"\e650"}.icon-plie:before{content:"\e651"}.icon-deplie:before{content:"\e652"}.icon-mailenvoi:before{content:"\e653"}.icon-nok:before{content:"\e654"}.icon-active:before{content:"\e655"}.icon-desactive:before{content:"\e656"}.icon-supprutilisateur:before{content:"\e657"}.icon-valideutilisateur:before{content:"\e658"}.icon-lecture:before{content:"\e659"}.icon-nolecture:before{content:"\e65a"}.icon-echange:before{content:"\e65b"}.icon-notes:before{content:"\e65c"}.icon-cdt:before{content:"\e65d"}
\ No newline at end of file
diff -urN cahier-de-prepa8.1.1/css/style.css cahier-de-prepa9.0.0/css/style.css
--- cahier-de-prepa8.1.1/css/style.css	2018-10-28 01:06:24.017445327 +0200
+++ cahier-de-prepa9.0.0/css/style.css	2019-08-28 18:08:33.383559955 +0200
@@ -1,9 +1,9 @@
 /* Feuille de style général : tailles et positionnements */
 
-/* Couleurs :
- * #99B3E5 : menus à gauche (HSL: 220,60,75)
- * #CDD5E4 : article        (HSL: 220,30,85)
- * #E7EEFE : fenêtre        (HSL: 220,90,95)
+/* Couleurs (version desktop/version mobile) :
+ * #99B3E5(HSL: 220,60,75) : menus/icones
+ * #CDD5E4(HSL: 220,30,85) : articles
+ * #E7EEFE(HSL: 220,90,95) : fenêtre/fenêtre+menu
  * #BA0D1F : rouge annonces
  * #001030,#002877 : titres/liens dans menus à gauche
  * #F6F6F6 : fond
@@ -33,60 +33,62 @@
 div, p, section, article { text-align: justify; }
 
 /* Blocs principaux, icônes */
+#iconesmenu { background-color: #99B3E5; text-align-last: justify; }
+#iconesmenu a { padding: 0 3px; color: #001030; }
+#iconesmenu a:hover { color: #CDF; }
+#iconesmenu .icon-recent::before{ font-size: 2em; }
+#iconesmenu .icon-recent { font-size: 0.5em; }
+nav > a { display: block; margin-bottom: 0.2em; text-decoration: none; color: #002877; }
+nav h3 { font-size: 1.2em; margin: 0.5em 3% 0.1em; padding-top: 0.3em; color: #001030; border-top: 1px solid #001030; }
+#actuel { font-style: italic; }
 section > :first-child, article > :first-child, article > h2:first-of-type, article > h3:first-of-type, #fenetre h3:first-of-type { margin-top: 0; }
 article > :last-child, #fenetre > :last-child { margin-bottom: 0; }
-article { margin-bottom: 1em; padding: 1em 2%; background-color: #CDD5E4; }
-#fenetre { position: fixed; left: 50%; z-index: 15; padding: 1em 2%; overflow: auto;
-           background-color: #E7EEFE; opacity: 0.97; box-shadow: 0.5em 0.5em 0.5em #777; }
+article { margin-bottom: 1em; padding: 1em 2%; background-color: #CDD5E4; overflow-x: auto; }
+#fenetre { position: fixed; z-index: 15; padding: 1em 2% 0; background-color: #E7EEFE; opacity: 0.97; box-shadow: 0.5em 0.5em 0.5em #777; }
+#fenetre:after { content: ""; display: block; height: 1em; width: 100%; } /*bug Firefox qui supprime le padding si scroll*/
 #fenetre_fond { position: fixed; top: 0; left: 0; width: 100%; height: 100%;
                 background-color: #000; opacity: 0.2; z-index: 14; }
 article > a[class^="icon-"], #fenetre > a[class^="icon-"] { float: right; margin-left: 0.3em; }
 #fenetre hr { margin: 1.5em 0; }
 footer { text-align: center; width: 90%; padding: 1em 5%; clear: both; position: fixed; left: 0; bottom: 0; z-index: 20;
          border-top: 1px solid black; background-color: #DDD; opacity: 0.97; }
-
+ 
 /* Blocs principaux, affichage différentiés selon la taille de l'écran */
 @media screen and (min-width: 800px) {
-  #colonne { width: 280px; float: left; margin: 0 30px 3em; }
-  nav { padding: 1em 20px 0.7em; }
-  .icon-menu, .icon-recent { display: none; }
-  #recent { margin-top: 1.5em; padding: 1em 20px; }
+  #iconesmenu { width: 240px; padding: 0.7em 0 0.5em; }
+  #iconesmenu a:first-child { display: none; }
+  nav { float: left; width: 240px; margin: 0 30px; padding: 0.7em 20px 0.5em; padding-top: 0.1em; margin-bottom: 3em; background-color: #99B3E5; }
+  nav hr { margin: 0 3% 0.7em; color: #001030; border-top: 1px solid #001030; border-bottom: none; }
+  nav a:hover { color: #CDF; }
   section { position: relative; margin: 0 30px 0 340px; padding-bottom: 3em;  }
   #icones { position: absolute; top: -4em; right: 0; }
   header + section { width: 96%; margin: 0 auto; max-width: 1500px; text-align: center;}
   footer { font-size: 0.8em; }
-  #fenetre { top: 10%; width: 70%; margin-left: -37%; max-height: 80%; }
+  #fenetre { top: 10%; left: 0; right: 0; width: 70%; margin: 0 auto; max-height: calc(90% - 7em); }
+  p.ligne input, p.ligne select, p.ligne code { width: 65%; }
 }
 @media screen and (max-width: 800px) {
+  body { padding-top: 2.2em; }
   h1 { font-size: 1.8em; padding: 0.3em 3em; }
   h2 { font-size: 1.65em; }
-  #colonne { display: none; }
-  #colonne.visible { display: block; }
-  nav.visible, #recent.visible { display: block; position: fixed; z-index: 10; top: 3.3em; left: 0.5em; padding: 1em 20px 0.7em;
-                                 width: 80%; min-width: 200px; max-width: 280px; max-height: 70%; overflow: auto; box-shadow: 0.5em 0.5em 0.5em #777; }
-  .icon-menu, .icon-recent { position: fixed; z-index: 10; top: 0.8em; left: 0.5em; font-size: 1.2em; cursor: pointer; }
-  .icon-recent { left: 2.5em; }
+  #iconesmenu { position: fixed; top: 0; left: 0; z-index: 20; width: 100%; min-width: 320px; height: 1.4em; border-bottom: 1px solid black; padding: 0.4em 0; }
+  #iconesmenu a:first-child { padding-left: 20px; }
+  #iconesmenu a:last-child { padding-right: 20px; }
+  #iconesmenu [class="icon-imprime"] { display: none; }
+  nav { position: fixed; top: 2.2em; left: 0; z-index: 19; height: calc(100% - 5.4em); width: 0; padding: 0.5em 0 0.7em; overflow-x: hidden; overflow-y: auto; transition: all 1s ease-in-out; background-color: #E7EEFE; }
+  nav.visible { display: block; width: 80%; padding: 0.5em 20px 0.7em; }
+  #menu_fond { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #000; opacity: 0.2; z-index: 18; }
+  nav > a, nav h3 { white-space: pre; }
+  nav hr:first-of-type { display: none; }
+  nav > a:last-child { padding-bottom: 0.5em; }
   section { position: relative; width:96%; margin: 0 auto; padding-bottom: 3em; }
   #icones { position: absolute; top: -2.2em; right: 0; }
   header + section { text-align: center; }
-  footer { font-size: 0.6em; }
-  #fenetre { top: 4%; width: 92%; margin-left: -48%; max-height: 92%; }
+  footer { font-size: 0.6em; height: 1.4em; }
+  #fenetre { top: 3em; left: 0; right: 0; width: 92%; margin: 0 auto; max-height: calc(100% - 8em); }
+  p.ligne input, p.ligne select, p.ligne code { width: 35%; }
 }
 
-/* Dans le menu et dans les informations récentes*/
-nav, #recent { background-color: #99B3E5; }
-nav a[class^="icon-"] { display: inline-block; margin: 0 0.3em; color: #001030; }
-nav a { display: block; margin-bottom: 0.2em; text-decoration: none; color: #002877; }
-nav a:hover { color: #CDF; }
-nav h3 { font-size: 1.2em; margin: 0.5em 3% 0.1em; padding-top: 0.3em; color: #001030; border-top: 1px solid #001030; }
-nav hr { margin: 0.5em 3% 0.5em; color: #001030; border-top: 1px solid #001030; border-bottom: none; }
-nav a.menurep { padding-left: 3%; font-size: 0.9em; }
-#actuel { font-style: italic; }
-nav h3 span { font-weight: 500; font-size: 0.83em; margin-right: 0.2em; color: #001030 !important; }
-#recent a { display: block; margin-bottom: 0.4em; text-decoration: none; color: #002877; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
-#recent a span { color: #002877; }
-#recent h3 { font-size: 1.2em; margin: 0 3% 0.5em; color: #001030; }
- 
 /* PDF et JPG */
 .pdf { height: 0; width: 100%; overflow: hidden; position: relative; }
 .portrait { padding-bottom: 138%; }
@@ -97,69 +99,62 @@
 /* Spécial */
 .warning { text-align: center; width: 50%; margin: 1em auto; padding: 0.5em 3%; }
 .annonce { margin: 1em 3%; padding: 0.5em 4%; }
-.note { margin: 0.5em 2%; padding: 0 4%; }
+.note { margin: 0.5em 2%; padding: 0 4%; color: #BA0D1F; }
 .warning, .annonce { color: #BA0D1F; border: 2px solid #BA0D1F; }
-.note { color: #BA0D1F; }
 .oubli { font-size: 0.8em; text-align: center; }
 .oubli a { text-decoration: none; color: #333; }
 .oubli label { font-weight: 700; }
 .oubli input { margin-left: 1em; vertical-align: text-top; }
 p.titrecdt { text-align: right; text-decoration: underline; }
 p.titrecdt.edition { text-align: left; text-decoration: none; padding-right: 1%; }
-.topbarre { height: 1.5em; background-color: #DDD; border: 1px solid #BBB; width: auto; border-radius: 4px; margin-bottom: 1.5em; }
 h1 span { font-size: 70%; vertical-align: 7%; margin-left: 0.4em; } /* indication de protection en mode édition */
 
-/* Menu de recherche, programme de colle et cahier de texte */
-#recherchecdt a, #recherchecolle a, #rechercheagenda a { margin-right: 0.4em; vertical-align: middle; }
-.topbarre select#semaines { margin-left: 0.8em; width: 8.5em; }
-.topbarre select#seances { margin-left: 0.8em; width: 11em; }
-.topbarre input { position: absolute; top: 0.25em; margin:0 0.8em 0 1em; padding-left: 1.8em; width: -moz-available; }
-.topbarre input, .topbarre select { font-size: 0.9em; height: 1.25em; vertical-align: bottom; }
-.topbarre .icon-recherche { position: relative; left: 1.9em; font-size: 0.7em; cursor: pointer; }
-/* Disparition de la case de recherche */
-@media screen and (max-width: 980px) and (min-width: 800px), screen and (max-width: 600px) {
-  #recherchecdt input { display: none; top: 1.8em; padding-left: 0.1em; right: 2em; margin-left: 2em !important; }
-  #recherchecdt span { left: 1.3em; }
-}
-@media screen and (max-width: 450px) {
-  #recherchecdt a, #recherchecdt select { margin-left: 0.3em !important; }
-  #recherchecdt input { margin-left: 0.3em; }
-  #recherchecdt select { width: 6em !important; }
-  #recherchecdt span { left: 0.3em; }
-}
-@media screen and (max-width: 400px) {
-  #recherchecolle a, #recherchecolle select { margin-left: 0.3em !important; }
-  #recherchecolle input { margin-left: 0 !important; }
-  #recherchecolle select { width: 6em; }
-  #recherchecolle span { left: 0.3em; }
-}
-@media screen and (max-width: 350px) {
-  #recherchecolle input { display: none; top: 1.8em; padding-left: 0.1em; right: 2em; margin-left: 2em !important; }
+/* Barre de recherche (programme de colle, cahier de texte, documents, contenus récents, agenda, notes)*/
+.topbarre { min-height: 1.6em; background-color: #DDD; border: 1px solid #BBB; width: auto; border-radius: 4px; padding: 0 1em 0.2em; margin-bottom: 1.5em; }
+.topbarre * { margin-right: 0.4em; vertical-align: middle; }
+.topbarre *:last-child { margin-right: 0em; }
+.topbarre a { width: 1em; }
+.topbarre input, .topbarre select { font-size: 0.8em; height: 1.4em; }
+#recherchecolle input { padding-left: 1.8em; width: calc(100% - 16.1em); }
+#recherchecdt input { padding-left: 1.8em; width: calc(100% - 28.1em); }
+#rechercherecent input { padding-left: 1.8em; width: calc(100% - 25.5em); }
+.topbarre select#seances { width: 11em; }
+.topbarre select#semaines { width: 9em; }
+#rechercherecent select { width: 12em; }
+.topbarre .icon-recherche { position: absolute; top: 0.75em; font-size: 0.7em; cursor: pointer; }
+#recherchecolle .icon-recherche { left: 20.5em; }
+#recherchecdt .icon-recherche { left: 33.7em; }
+#rechercherecent .icon-recherche { left: 31.2em; }
+#parentsdoc > a[class^="icon-"] { float: right; margin: 0.4em 0 0 0.3em; }
+#parentsdoc .nom { font-weight: 700; } 
+#parentsdoc .nom a { text-decoration: none; color: black; margin: 0; vertical-align: baseline; }
+/* Pour les petits écrans, barre sur deux lignes */
+@media screen and (max-width: 500px) {
+  #recherchecdt select#seances { width: calc(65% - 6.5em); margin: 0; }
+  #recherchecdt select#semaines { width: 35%; margin: 0; }
+  #rechercherecent select { margin: 0; width: calc(50% - 0.3em); }
+  #recherchecdt .icon-recherche, #rechercherecent .icon-recherche { left: 2.1em; top: 2.8em }
+  #recherchecdt input, #rechercherecent input { width: 100%; margin-top: 0.2em; }
 }
 
-/* Spécifique webkit
-@media screen and (-webkit-min-device-pixel-ratio:0) { 
-  .topbarre { height: 1.4em; vertical-align: bottom; }
-  #recherchecolle input { width: 40%; }
-  .topbarre span { top: 0.2em; }
-  #recherchecdt a, #recherchecolle a { vertical-align: middle; }
-}*/
-
 /* Documents */
-#parentsdoc { margin-bottom: 1.5em; padding: 0.3em 2% 0; line-height: 1.3em; }
-#parentsdoc span { position: static; cursor: auto; }
 .rep, .doc { margin: 0 2%; padding: 0; border-bottom:  1px dotted #BBB; line-height: 1.3em; }
 .repcontenu, .docdonnees { float: right; font-size: 0.8em; padding-left: 0.5em; line-height: 1.625em; }
-#parentsdoc > a[class^="icon-"], .rep > a[class^="icon-"], .doc > a[class^="icon-"] { float: right; margin-left: 0.3em; line-height: 1.3em; }
-#parentsdoc a, .rep a, .doc a { text-decoration: none; color: black; }
-#parentsdoc .nom, .rep .nom, .doc .nom { font-weight: 700; margin-left: 0.5em; }
+.rep > a[class^="icon-"], .doc > a[class^="icon-"] { float: right; margin-left: 0.3em; line-height: 1.3em; }
+.rep a, .doc a { text-decoration: none; color: black; }
+.rep .nom, .doc .nom { font-weight: 700; margin-left: 0.5em; }
+
+/* Contenus récents */
+.recents h3 { margin: 0; }
+.recents h3 * { text-decoration: none; color: #001030; }
+.recents .publi { font-size: 0.8em; padding: 0em 5px 0.3em; color: #002877; }
 
 /* Édition : positionnements globaux */
 .edition { display: inline; text-align: left; padding-right: 3em; }
 h3.edition.editable { padding-right: 1%; }
 .edition + p, .edition ~ form { margin-top: 0.75em; }
 article.cache { background-color: #AAA; opacity: 0.6; }
-#log { position: fixed; top:3%; left: 3%; padding: 0.3em 2%; z-index: 20; margin-right: 3%; }
+#log { position: fixed; top:3%; left: 3%; padding: 0.3em 2%; z-index: 25; margin-right: 3%; }
 .ok { background-color: #EFE; color: #090; border: 1px solid #090; }
 .nok { background-color: #FEE; color: #D00; border: 1px solid #D00; }
 .ok span { color: #090; }
@@ -175,12 +170,13 @@
 #fenetre.usergrp .ligne { border-bottom: 1px dotted #BBB; }
 #fenetre.usergrp input { margin-top: 0.2em; }
 .protection { font-size: 0.8em; color: #999; } /* texte indiquant la protection des icônes */
+#rgpd p { font-size: 0.8em} /* texte d'information, page de préférences */
 
 /* Édition : formulaires */
-input, select, textarea { box-sizing: border-box; -webkit-box-sizing: border-box; border: 1px solid; border-radius: 2px; padding: 0 0.3em; }
+input, select, textarea { box-sizing: border-box; border: 1px solid; border-radius: 2px; padding: 0 0.3em; }
 #fichier { border: none; font-size: 0.8em; height: 1.9em; }
 p.ligne label { font-weight: 700; }
-p.ligne input, p.ligne select, p.ligne code { width: 65%; float: right; margin-left: 0.2em; font-size: 0.8em; height: 1.6em; }
+p.ligne input, p.ligne select, p.ligne code { float: right; margin-left: 0.2em; font-size: 0.8em; height: 1.6em; } 
 p.ligne input[type="checkbox"], p.ligne input[type="radio"] { width: 1em; }
 input.ligne { width: 96%;  margin: 0.5em 2%; height: 1.6em; font-size: 0.8em; display: block; }
 p.ligne + * { clear: right; }
@@ -189,18 +185,22 @@
 .gestion_protection input { vertical-align: sub; }
 .supprmultiple { margin-top: 0.3em; margin-bottom: 0 !important; }
 
-/* Tableaux */
+/* Tableaux : général */
 table { width: 100%; margin: 1em 0; border-collapse: collapse; border: medium solid #999; }
-table td { padding: 0.15em 0.5%; }
-table th { padding: 0.15em 3%; }
-table td, table th { border: thin solid #AAA; }
+table td, table th { padding: 0.15em 0.3em 0; border: thin solid #AAA; }
 .centre, #planning, #notes { text-align: center; }
 .centre th { padding: 0.15em 0; }
 tr[data-id]:hover, #planning tbody tr:hover, #fenetre tbody tr:not(.categorie):hover { background-color: #EFF; }
+
+/* Tableaux : selection multiple */
 #selmult { width: auto; min-width: 70%; margin: 2em auto; padding-bottom: 2em; }
-#selmult td { border: none; padding-left: 5%; font-weight: 700; }
+#selmult th, #selmult td { border: none; }
+#selmult tr { border-top: none; border-left: none; border-right: none; border-bottom: 1px dotted #BBB; }
+#selmult td { padding-left: 5%; font-weight: 700; }
 #selmult .element td:first-child { padding-left: 10%; font-weight: 500; }
-#selmult td+td {vertical-align: sub; text-align: center; width: 5em; padding: 0.1em; }
+#selmult th+th, #selmult td+td {vertical-align: sub; text-align: center; width: 5em; padding: 0.1em; }
+#selmult input { vertical-align: sub; }
+.sel { background-color: #EFF; }
 
 /* Édition : champs éditables */
 .editable, .titrecdt.edition, form.titrecdt { border: 1px dotted #BBB; position: relative; }
@@ -209,7 +209,7 @@
 h3.editable a[class^="icon-"], h3 span.editable a[class^="icon-"] { font-weight: 500; font-size: 0.67em; padding-top: 0.1em;}
 h3.avecform span { font-weight: 500; font-size: 0.6em; margin-top: 0.5em; width: 80%; overflow: hidden; white-space:nowrap; }
 h3.avecform input { width: 50%; }
-textarea, [contenteditable=true].ligne { width: 96%; margin: 0.5em 2%; }
+textarea, [contenteditable=true].ligne { width: calc(100% - 3em); margin: 0 1.5em; }
 textarea + div { min-height: 6em; border: 1px dotted #CCC; background-color: #FFF; }
 .boutons { clear: right; background-color: #DDD; border: 1px solid #BBB; width: auto; padding: 0; margin-bottom: 0; border-radius: 4px; }
 .boutons button { cursor: default; background-color: transparent;
@@ -237,31 +237,28 @@
 td.pasnote { font-style: italic; text-align: center; }
 .collsel { font-weight: 700; }
 .collnosel, .dejanote { color: #AAA; }
-#recherchenote { padding: 0px 1em; }
 #tableaunotes td+td { text-align: right;}
 /* th.semaines réglés comme th.matieres et th.colleurs */
 
 /* Tableau d'utilisateurs : mail, groupes, utilisateurs, utilisateurs-matieres */
-.sel { background-color: #EFF; }
-#utilisateurs tr, #selmult tr { border-top: none; border-left: none; border-right: none; border-bottom: 1px dotted #BBB; }
-#utilisateurs th, #utilisateurs td, #utilisateurs-matieres th, #utilisateurs-matieres td { border: 1px dotted #BBB; }
-#fenetre #utilisateurs th, #fenetre #utilisateurs td { border: none; }
-#fenetre #utilisateurs th+th, #fenetre #utilisateurs td+td { text-align: center; width: 5em; padding: 0.1em; }
-#utilisateurs input, #utilisateurs-matieres input, #selmult input { vertical-align: sub; }
-.categorie th+th, #utilisateurs-matieres td+td { text-align: center; padding: 0; }
-#utilisateurs .icones { width: 1em; white-space: nowrap; padding: 0.15em 0.3em; font-weight: normal; text-align: right; }
-#utilisateurs .icones * { font-weight: normal; vertical-align: middle; padding: 0; margin: 0; }
-#utilisateurs .icones input { width: 1em; }
-#utilisateurs .icones a { display: inline-block; width: 1em; }
-.categorie th { border: none !important; }
-.categorie span { cursor:pointer; }
-th.semaines, th.matieres, th.colleurs { vertical-align: bottom; padding: 1em 0; text-align: center; }
-th.semaines { width: 1.7em; }
-th.semaines span, th.matieres span, th.colleurs span { display:inline-block;
-  writing-mode: vertical-lr; -webkit-writing-mode: vertical-rl;
-  transform: rotate(180deg); -webkit-transform: rotate(180deg);
-  white-space: nowrap;
-}
+.utilisateurs th, .utilisateurs td { border: 1px dotted #BBB; }
+.utilisateurs .icone { text-align: center; width: 1.4em; }
+#fenetre .utilisateurs .icone { width: 5em; padding: 0; }
+.categorie th:first-child { padding-left: 3%; }
+.utilisateurs .icones { width: 1em; white-space: nowrap; font-weight: normal; text-align: right; }
+.utilisateurs .icones * { font-weight: normal; padding: 0; margin: 0; }
+.utilisateurs .icones input { width: 1em; }
+.utilisateurs .icones a { display: inline-block; width: 1em; }
+.categorie span, #envoimails span { cursor:pointer; }
+/* Pour le pliage-dépliage */
+.utilisateurs .cache { padding: 0 0.3em; }
+.utilisateurs .cache div { padding: 0.1em 0; width: 100%; }
+.utilisateurs .cache.icone div { text-align: center; }
+/* Planning annuel */
+#planning select { font-size: 0.8em; height: 1.6em; margin-bottom: 3px; }
+/* Parties verticales */
+th.vertical { vertical-align: bottom; padding: 1em 0; text-align: center; min-width: 1.4em; }
+th.vertical span { display:inline-block; white-space: nowrap; writing-mode: vertical-lr; -webkit-writing-mode: vertical-rl; transform: rotate(180deg); -webkit-transform: rotate(180deg); }
 
 /* Pour l'impression */
 @media print {
@@ -296,3 +293,8 @@
 /* Chargement pour les envoi ajax */
 #load { display: none; margin: 0; padding: 0; position: fixed; top: 0; left: 0; width: 100%; height: 100%; z-index: 30; text-align: center;}
 #load img { position: absolute; top: 50%; }
+
+/* Liste des Cahiers si interface globale */
+#cahiers { text-align: center; }
+#cahiers a { text-decoration: none; font-weight: 700; display: block; color: #000; }
+#cahiers a:hover { color: #002877; background-color: #E7EEFE; }
diff -urN cahier-de-prepa8.1.1/css/style.min.css cahier-de-prepa9.0.0/css/style.min.css
--- cahier-de-prepa8.1.1/css/style.min.css	2018-10-31 03:52:49.351200890 +0100
+++ cahier-de-prepa9.0.0/css/style.min.css	2019-08-28 19:37:25.609433710 +0200
@@ -1 +1 @@
-*{font-size:1em;margin:0;padding:0}html,body{height:100%}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;position:relative;width:100%;margin:0 auto;min-width:320px;max-width:1500px;background-color:#f6f6f6}h1{font-size:2.2em;text-align:center;padding:1em 2em}h2{font-size:1.8em;margin:1em 0 .8em}h3{font-size:1.5em;margin:1em 0 .5em}h2+h3{padding-left:1%}h4{font-size:1.3em;margin:.5em 0 .2em;padding-left:2.5%}h5{font-size:1.1em;margin-top:.2em;padding-left:4%}h6{font-size:1em;margin-top:.2em;padding-left:5.5%}ul,ol{margin:.5em 0;padding:0 2% 0 6%}p{padding:0 2%}p+p{margin-top:.5em}img{border:0;max-width:100%}div,p,section,article{text-align:justify}section>:first-child,article>:first-child,article>h2:first-of-type,article>h3:first-of-type,#fenetre h3:first-of-type{margin-top:0}article>:last-child,#fenetre>:last-child{margin-bottom:0}article{margin-bottom:1em;padding:1em 2%;background-color:#cdd5e4}#fenetre{position:fixed;left:50%;z-index:15;padding:1em 2%;overflow:auto;background-color:#e7eefe;opacity:.97;box-shadow:.5em .5em .5em #777}#fenetre_fond{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.2;z-index:14}article>a[class^="icon-"],#fenetre>a[class^="icon-"]{float:right;margin-left:.3em}#fenetre hr{margin:1.5em 0}footer{text-align:center;width:90%;padding:1em 5%;clear:both;position:fixed;left:0;bottom:0;z-index:20;border-top:1px solid black;background-color:#DDD;opacity:.97}@media screen and (min-width:800px){#colonne{width:280px;float:left;margin:0 30px 3em}nav{padding:1em 20px .7em}.icon-menu,.icon-recent{display:none}#recent{margin-top:1.5em;padding:1em 20px}section{position:relative;margin:0 30px 0 340px;padding-bottom:3em}#icones{position:absolute;top:-4em;right:0}header+section{width:96%;margin:0 auto;max-width:1500px;text-align:center}footer{font-size:.8em}#fenetre{top:10%;width:70%;margin-left:-37%;max-height:80%}}@media screen and (max-width:800px){h1{font-size:1.8em;padding:.3em 3em}h2{font-size:1.65em}#colonne{display:none}#colonne.visible{display:block}nav.visible,#recent.visible{display:block;position:fixed;z-index:10;top:3.3em;left:.5em;padding:1em 20px .7em;width:80%;min-width:200px;max-width:280px;max-height:70%;overflow:auto;box-shadow:.5em .5em .5em #777}.icon-menu,.icon-recent{position:fixed;z-index:10;top:.8em;left:.5em;font-size:1.2em;cursor:pointer}.icon-recent{left:2.5em}section{position:relative;width:96%;margin:0 auto;padding-bottom:3em}#icones{position:absolute;top:-2.2em;right:0}header+section{text-align:center}footer{font-size:.6em}#fenetre{top:4%;width:92%;margin-left:-48%;max-height:92%}}nav,#recent{background-color:#99b3e5}nav a[class^="icon-"]{display:inline-block;margin:0 .3em;color:#001030}nav a{display:block;margin-bottom:.2em;text-decoration:none;color:#002877}nav a:hover{color:#CDF}nav h3{font-size:1.2em;margin:.5em 3% .1em;padding-top:.3em;color:#001030;border-top:1px solid #001030}nav hr{margin:.5em 3% .5em;color:#001030;border-top:1px solid #001030;border-bottom:0}nav a.menurep{padding-left:3%;font-size:.9em}#actuel{font-style:italic}nav h3 span{font-weight:500;font-size:.83em;margin-right:.2em;color:#001030!important}#recent a{display:block;margin-bottom:.4em;text-decoration:none;color:#002877;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}#recent a span{color:#002877}#recent h3{font-size:1.2em;margin:0 3% .5em;color:#001030}.pdf{height:0;width:100%;overflow:hidden;position:relative}.portrait{padding-bottom:138%}.paysage{padding-bottom:74%}.hauteur50{padding-bottom:50%}.pdf object{position:absolute}.warning{text-align:center;width:50%;margin:1em auto;padding:.5em 3%}.annonce{margin:1em 3%;padding:.5em 4%}.note{margin:.5em 2%;padding:0 4%}.warning,.annonce{color:#ba0d1f;border:2px solid #ba0d1f}.note{color:#ba0d1f}.oubli{font-size:.8em;text-align:center}.oubli a{text-decoration:none;color:#333}.oubli label{font-weight:700}.oubli input{margin-left:1em;vertical-align:text-top}p.titrecdt{text-align:right;text-decoration:underline}p.titrecdt.edition{text-align:left;text-decoration:none;padding-right:1%}.topbarre{height:1.5em;background-color:#DDD;border:1px solid #BBB;width:auto;border-radius:4px;margin-bottom:1.5em}h1 span{font-size:70%;vertical-align:7%;margin-left:.4em}#recherchecdt a,#recherchecolle a,#rechercheagenda a{margin-right:.4em;vertical-align:middle}.topbarre select#semaines{margin-left:.8em;width:8.5em}.topbarre select#seances{margin-left:.8em;width:11em}.topbarre input{position:absolute;top:.25em;margin:0 .8em 0 1em;padding-left:1.8em;width:-moz-available}.topbarre input,.topbarre select{font-size:.9em;height:1.25em;vertical-align:bottom}.topbarre .icon-recherche{position:relative;left:1.9em;font-size:.7em;cursor:pointer}@media screen and (max-width:980px) and (min-width:800px),screen and (max-width:600px){#recherchecdt input{display:none;top:1.8em;padding-left:.1em;right:2em;margin-left:2em!important}#recherchecdt span{left:1.3em}}@media screen and (max-width:450px){#recherchecdt a,#recherchecdt select{margin-left:.3em!important}#recherchecdt input{margin-left:.3em}#recherchecdt select{width:6em!important}#recherchecdt span{left:.3em}}@media screen and (max-width:400px){#recherchecolle a,#recherchecolle select{margin-left:.3em!important}#recherchecolle input{margin-left:0!important}#recherchecolle select{width:6em}#recherchecolle span{left:.3em}}@media screen and (max-width:350px){#recherchecolle input{display:none;top:1.8em;padding-left:.1em;right:2em;margin-left:2em!important}}#parentsdoc{margin-bottom:1.5em;padding:.3em 2% 0;line-height:1.3em}#parentsdoc span{position:static;cursor:auto}.rep,.doc{margin:0 2%;padding:0;border-bottom:1px dotted #BBB;line-height:1.3em}.repcontenu,.docdonnees{float:right;font-size:.8em;padding-left:.5em;line-height:1.625em}#parentsdoc>a[class^="icon-"],.rep>a[class^="icon-"],.doc>a[class^="icon-"]{float:right;margin-left:.3em;line-height:1.3em}#parentsdoc a,.rep a,.doc a{text-decoration:none;color:black}#parentsdoc .nom,.rep .nom,.doc .nom{font-weight:700;margin-left:.5em}.edition{display:inline;text-align:left;padding-right:3em}h3.edition.editable{padding-right:1%}.edition+p,.edition ~ form{margin-top:.75em}article.cache{background-color:#AAA;opacity:.6}#log{position:fixed;top:3%;left:3%;padding:.3em 2%;z-index:20;margin-right:3%}.ok{background-color:#EFE;color:#090;border:1px solid #090}.nok{background-color:#FEE;color:#D00;border:1px solid #D00}.ok span{color:#090}.nok span{color:#D00}#log span{cursor:pointer;position:relative;right:-0.8em;top:.1em}[id^="aide-"],[id^="form-"]{display:none}#fenetre [name="titre"]{margin:2em 0 1em}#fenetre [name="titre"]+*{display:inline}form.titrecdt{padding:.2em 0 .5em;margin-top:.2em}.confirmation{text-align:center}#fenetre.usergrp .ligne{border-bottom:1px dotted #BBB}#fenetre.usergrp input{margin-top:.2em}.protection{font-size:.8em;color:#999}input,select,textarea{box-sizing:border-box;-webkit-box-sizing:border-box;border:1px solid;border-radius:2px;padding:0 .3em}#fichier{border:0;font-size:.8em;height:1.9em}p.ligne label{font-weight:700}p.ligne input,p.ligne select,p.ligne code{width:65%;float:right;margin-left:.2em;font-size:.8em;height:1.6em}p.ligne input[type="checkbox"],p.ligne input[type="radio"]{width:1em}input.ligne{width:96%;margin:.5em 2%;height:1.6em;font-size:.8em;display:block}p.ligne+*{clear:right}.gestion_protection{margin:0!important}.gestion_protection p{margin:0}.gestion_protection input{vertical-align:sub}.supprmultiple{margin-top:.3em;margin-bottom:0!important}table{width:100%;margin:1em 0;border-collapse:collapse;border:medium solid #999}table td{padding:.15em .5%}table th{padding:.15em 3%}table td,table th{border:thin solid #AAA}.centre,#planning,#notes{text-align:center}.centre th{padding:.15em 0}tr[data-id]:hover,#planning tbody tr:hover,#fenetre tbody tr:not(.categorie):hover{background-color:#EFF}#selmult{width:auto;min-width:70%;margin:2em auto;padding-bottom:2em}#selmult td{border:0;padding-left:5%;font-weight:700}#selmult .element td:first-child{padding-left:10%;font-weight:500}#selmult td+td{vertical-align:sub;text-align:center;width:5em;padding:.1em}.editable,.titrecdt.edition,form.titrecdt{border:1px dotted #BBB;position:relative}.editable a[class^="icon-"],p.titrecdt a[class^="icon-"],.maildest a[class^="icon-"]{padding-left:.3em}.avecform{border:none!important}h3.editable a[class^="icon-"],h3 span.editable a[class^="icon-"]{font-weight:500;font-size:.67em;padding-top:.1em}h3.avecform span{font-weight:500;font-size:.6em;margin-top:.5em;width:80%;overflow:hidden;white-space:nowrap}h3.avecform input{width:50%}textarea,[contenteditable=true].ligne{width:96%;margin:.5em 2%}textarea+div{min-height:6em;border:1px dotted #CCC;background-color:#FFF}.boutons{clear:right;background-color:#DDD;border:1px solid #BBB;width:auto;padding:0;margin-bottom:0;border-radius:4px}.boutons button{cursor:default;background-color:transparent;border-top:0;border-left:none;border-bottom:1px solid #BBB;border-right:1px solid #BBB;height:1.5em;font-size:100%;width:2em}.boutons button+button{margin-left:-0.2em}p.boutons.ligne{width:96%;margin:0 2%}[contenteditable=true]:empty:before{content:attr(placeholder);color:#999;font-size:.8em;display:block}div.editable a[class^="icon-"]{position:absolute;right:3px;top:0}div.editable a.icon-annule{top:1.5em}div.edithtml a.icon-ok{top:1.6em}div.edithtml a.icon-annule{top:3.1em}.icon-mailenvoi{font-size:2em}#notes th,#notes td{padding:.15em .5em}#notes .icones{text-align:left;padding:.15em .5em;width:2.3em}.notes td+td{width:6em;text-align:center}.notes td+td select{width:6em;font-size:.8em;margin-bottom:.2em}.notes+p.ligne{clear:right;margin-top:.5em}td.pasnote{font-style:italic;text-align:center}.collsel{font-weight:700}.collnosel,.dejanote{color:#AAA}#recherchenote{padding:0 1em}#tableaunotes td+td{text-align:right}.sel{background-color:#EFF}#utilisateurs tr,#selmult tr{border-top:0;border-left:none;border-right:0;border-bottom:1px dotted #BBB}#utilisateurs th,#utilisateurs td,#utilisateurs-matieres th,#utilisateurs-matieres td{border:1px dotted #BBB}#fenetre #utilisateurs th,#fenetre #utilisateurs td{border:0}#fenetre #utilisateurs th+th,#fenetre #utilisateurs td+td{text-align:center;width:5em;padding:.1em}#utilisateurs input,#utilisateurs-matieres input,#selmult input{vertical-align:sub}.categorie th+th,#utilisateurs-matieres td+td{text-align:center;padding:0}#utilisateurs .icones{width:1em;white-space:nowrap;padding:.15em .3em;font-weight:normal;text-align:right}#utilisateurs .icones *{font-weight:normal;vertical-align:middle;padding:0;margin:0}#utilisateurs .icones input{width:1em}#utilisateurs .icones a{display:inline-block;width:1em}.categorie th{border:none!important}.categorie span{cursor:pointer}th.semaines,th.matieres,th.colleurs{vertical-align:bottom;padding:1em 0;text-align:center}th.semaines{width:1.7em}th.semaines span,th.matieres span,th.colleurs span{display:inline-block;writing-mode:vertical-lr;-webkit-writing-mode:vertical-rl;transform:rotate(180deg);-webkit-transform:rotate(180deg);white-space:nowrap}@media print{body{font-size:90%;font-family:Serif}#colonne,#recherchecolle,#recherchecdt,#rechercheagenda,[id^="aide-"],[id^="form-"],footer,a[class^="icon-"]{display:none}.editable,.titrecdt.edition,form.titrecdt{border:0}h1{font-size:1.7em}h2{font-size:1.5em;margin:.7em 0}h3{font-size:1.35em;margin:.6em 0}h4{font-size:1.2em;margin:.4em 0 .2em}article{border:1px solid #999}table th{padding:.15em .5%}}#calendrier{margin-top:1em}#calendrier table{table-layout:fixed}#semaine,.semaine-bg,.evenements{margin:0}#semaine{font-weight:900;text-align:center}#semaine th{overflow:hidden;text-overflow:clip}.semaine-bg{border-top:0;position:absolute;z-index:1}.autremois{background-color:#e7eefe;color:#002877}#aujourdhui{background-color:#99b3e5}.evenements{position:relative;z-index:2;border-top:0;border-bottom:0}.evenements thead{border-bottom:1px solid #999}.evenements th{padding:.15em .5%;text-align:right}.evenements td{padding:2px 3px 1px;border:none!important}.modifevnmt{padding:1px 3px;border-radius:5px;white-space:nowrap;overflow:hidden;font-size:.8em;cursor:pointer}.evnmt_suivi{border-top-right-radius:0;border-bottom-right-radius:0;margin-right:-2px}.evnmt_suite{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-3px}#load{display:none;margin:0;padding:0;position:fixed;top:0;left:0;width:100%;height:100%;z-index:30;text-align:center}#load img{position:absolute;top:50%}
\ No newline at end of file
+*{font-size:1em;margin:0;padding:0}html,body{height:100%}body{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;position:relative;width:100%;margin:0 auto;min-width:320px;max-width:1500px;background-color:#f6f6f6}h1{font-size:2.2em;text-align:center;padding:1em 2em}h2{font-size:1.8em;margin:1em 0 .8em}h3{font-size:1.5em;margin:1em 0 .5em}h2+h3{padding-left:1%}h4{font-size:1.3em;margin:.5em 0 .2em;padding-left:2.5%}h5{font-size:1.1em;margin-top:.2em;padding-left:4%}h6{font-size:1em;margin-top:.2em;padding-left:5.5%}ul,ol{margin:.5em 0;padding:0 2% 0 6%}p{padding:0 2%}p+p{margin-top:.5em}img{border:0;max-width:100%}div,p,section,article{text-align:justify}#iconesmenu{background-color:#99b3e5;text-align-last:justify}#iconesmenu a{padding:0 3px;color:#001030}#iconesmenu a:hover{color:#CDF}#iconesmenu .icon-recent::before{font-size:2em}#iconesmenu .icon-recent{font-size:.5em}nav>a{display:block;margin-bottom:.2em;text-decoration:none;color:#002877}nav h3{font-size:1.2em;margin:.5em 3% .1em;padding-top:.3em;color:#001030;border-top:1px solid #001030}#actuel{font-style:italic}section>:first-child,article>:first-child,article>h2:first-of-type,article>h3:first-of-type,#fenetre h3:first-of-type{margin-top:0}article>:last-child,#fenetre>:last-child{margin-bottom:0}article{margin-bottom:1em;padding:1em 2%;background-color:#cdd5e4;overflow-x:auto}#fenetre{position:fixed;z-index:15;padding:1em 2% 0;background-color:#e7eefe;opacity:.97;box-shadow:.5em .5em .5em #777}#fenetre:after{content:"";display:block;height:1em;width:100%}#fenetre_fond{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.2;z-index:14}article>a[class^="icon-"],#fenetre>a[class^="icon-"]{float:right;margin-left:.3em}#fenetre hr{margin:1.5em 0}footer{text-align:center;width:90%;padding:1em 5%;clear:both;position:fixed;left:0;bottom:0;z-index:20;border-top:1px solid black;background-color:#DDD;opacity:.97}@media screen and (min-width:800px){#iconesmenu{width:240px;padding:.7em 0 .5em}#iconesmenu a:first-child{display:none}nav{float:left;width:240px;margin:0 30px;padding:.7em 20px .5em;padding-top:.1em;margin-bottom:3em;background-color:#99b3e5}nav hr{margin:0 3% .7em;color:#001030;border-top:1px solid #001030;border-bottom:0}nav a:hover{color:#CDF}section{position:relative;margin:0 30px 0 340px;padding-bottom:3em}#icones{position:absolute;top:-4em;right:0}header+section{width:96%;margin:0 auto;max-width:1500px;text-align:center}footer{font-size:.8em}#fenetre{top:10%;left:0;right:0;width:70%;margin:0 auto;max-height:calc(90% - 7em)}p.ligne input,p.ligne select,p.ligne code{width:65%}}@media screen and (max-width:800px){body{padding-top:2.2em}h1{font-size:1.8em;padding:.3em 3em}h2{font-size:1.65em}#iconesmenu{position:fixed;top:0;left:0;z-index:20;width:100%;min-width:320px;height:1.4em;border-bottom:1px solid black;padding:.4em 0}#iconesmenu a:first-child{padding-left:20px}#iconesmenu a:last-child{padding-right:20px}#iconesmenu [class="icon-imprime"]{display:none}nav{position:fixed;top:2.2em;left:0;z-index:19;height:calc(100% - 5.4em);width:0;padding:.5em 0 .7em;overflow-x:hidden;overflow-y:auto;transition:all 1s ease-in-out;background-color:#e7eefe}nav.visible{display:block;width:80%;padding:.5em 20px .7em}#menu_fond{position:fixed;top:0;left:0;width:100%;height:100%;background-color:#000;opacity:.2;z-index:18}nav>a,nav h3{white-space:pre}nav hr:first-of-type{display:none}nav>a:last-child{padding-bottom:.5em}section{position:relative;width:96%;margin:0 auto;padding-bottom:3em}#icones{position:absolute;top:-2.2em;right:0}header+section{text-align:center}footer{font-size:.6em;height:1.4em}#fenetre{top:3em;left:0;right:0;width:92%;margin:0 auto;max-height:calc(100% - 8em)}p.ligne input,p.ligne select,p.ligne code{width:35%}}.pdf{height:0;width:100%;overflow:hidden;position:relative}.portrait{padding-bottom:138%}.paysage{padding-bottom:74%}.hauteur50{padding-bottom:50%}.pdf object{position:absolute}.warning{text-align:center;width:50%;margin:1em auto;padding:.5em 3%}.annonce{margin:1em 3%;padding:.5em 4%}.note{margin:.5em 2%;padding:0 4%;color:#ba0d1f}.warning,.annonce{color:#ba0d1f;border:2px solid #ba0d1f}.oubli{font-size:.8em;text-align:center}.oubli a{text-decoration:none;color:#333}.oubli label{font-weight:700}.oubli input{margin-left:1em;vertical-align:text-top}p.titrecdt{text-align:right;text-decoration:underline}p.titrecdt.edition{text-align:left;text-decoration:none;padding-right:1%}h1 span{font-size:70%;vertical-align:7%;margin-left:.4em}.topbarre{min-height:1.6em;background-color:#DDD;border:1px solid #BBB;width:auto;border-radius:4px;padding:0 1em .2em;margin-bottom:1.5em}.topbarre *{margin-right:.4em;vertical-align:middle}.topbarre *:last-child{margin-right:0}.topbarre a{width:1em}.topbarre input,.topbarre select{font-size:.8em;height:1.4em}#recherchecolle input{padding-left:1.8em;width:calc(100% - 16.1em)}#recherchecdt input{padding-left:1.8em;width:calc(100% - 28.1em)}#rechercherecent input{padding-left:1.8em;width:calc(100% - 25.5em)}.topbarre select#seances{width:11em}.topbarre select#semaines{width:9em}#rechercherecent select{width:12em}.topbarre .icon-recherche{position:absolute;top:.75em;font-size:.7em;cursor:pointer}#recherchecolle .icon-recherche{left:20.5em}#recherchecdt .icon-recherche{left:33.7em}#rechercherecent .icon-recherche{left:31.2em}#parentsdoc>a[class^="icon-"]{float:right;margin:.4em 0 0 .3em}#parentsdoc .nom{font-weight:700}#parentsdoc .nom a{text-decoration:none;color:black;margin:0;vertical-align:baseline}@media screen and (max-width:500px){#recherchecdt select#seances{width:calc(65% - 6.5em);margin:0}#recherchecdt select#semaines{width:35%;margin:0}#rechercherecent select{margin:0;width:calc(50% - .3em)}#recherchecdt .icon-recherche,#rechercherecent .icon-recherche{left:2.1em;top:2.8em}#recherchecdt input,#rechercherecent input{width:100%;margin-top:.2em}}.rep,.doc{margin:0 2%;padding:0;border-bottom:1px dotted #BBB;line-height:1.3em}.repcontenu,.docdonnees{float:right;font-size:.8em;padding-left:.5em;line-height:1.625em}.rep>a[class^="icon-"],.doc>a[class^="icon-"]{float:right;margin-left:.3em;line-height:1.3em}.rep a,.doc a{text-decoration:none;color:black}.rep .nom,.doc .nom{font-weight:700;margin-left:.5em}.recents h3{margin:0}.recents h3 *{text-decoration:none;color:#001030}.recents .publi{font-size:.8em;padding:0 5px .3em;color:#002877}.edition{display:inline;text-align:left;padding-right:3em}h3.edition.editable{padding-right:1%}.edition+p,.edition ~ form{margin-top:.75em}article.cache{background-color:#AAA;opacity:.6}#log{position:fixed;top:3%;left:3%;padding:.3em 2%;z-index:25;margin-right:3%}.ok{background-color:#EFE;color:#090;border:1px solid #090}.nok{background-color:#FEE;color:#D00;border:1px solid #D00}.ok span{color:#090}.nok span{color:#D00}#log span{cursor:pointer;position:relative;right:-0.8em;top:.1em}[id^="aide-"],[id^="form-"]{display:none}#fenetre [name="titre"]{margin:2em 0 1em}#fenetre [name="titre"]+*{display:inline}form.titrecdt{padding:.2em 0 .5em;margin-top:.2em}.confirmation{text-align:center}#fenetre.usergrp .ligne{border-bottom:1px dotted #BBB}#fenetre.usergrp input{margin-top:.2em}.protection{font-size:.8em;color:#999}#rgpd p{font-size:.8em}input,select,textarea{box-sizing:border-box;border:1px solid;border-radius:2px;padding:0 .3em}#fichier{border:0;font-size:.8em;height:1.9em}p.ligne label{font-weight:700}p.ligne input,p.ligne select,p.ligne code{float:right;margin-left:.2em;font-size:.8em;height:1.6em}p.ligne input[type="checkbox"],p.ligne input[type="radio"]{width:1em}input.ligne{width:96%;margin:.5em 2%;height:1.6em;font-size:.8em;display:block}p.ligne+*{clear:right}.gestion_protection{margin:0!important}.gestion_protection p{margin:0}.gestion_protection input{vertical-align:sub}.supprmultiple{margin-top:.3em;margin-bottom:0!important}table{width:100%;margin:1em 0;border-collapse:collapse;border:medium solid #999}table td,table th{padding:.15em .3em 0;border:thin solid #AAA}.centre,#planning,#notes{text-align:center}.centre th{padding:.15em 0}tr[data-id]:hover,#planning tbody tr:hover,#fenetre tbody tr:not(.categorie):hover{background-color:#EFF}#selmult{width:auto;min-width:70%;margin:2em auto;padding-bottom:2em}#selmult th,#selmult td{border:0}#selmult tr{border-top:0;border-left:none;border-right:0;border-bottom:1px dotted #BBB}#selmult td{padding-left:5%;font-weight:700}#selmult .element td:first-child{padding-left:10%;font-weight:500}#selmult th+th,#selmult td+td{vertical-align:sub;text-align:center;width:5em;padding:.1em}#selmult input{vertical-align:sub}.sel{background-color:#EFF}.editable,.titrecdt.edition,form.titrecdt{border:1px dotted #BBB;position:relative}.editable a[class^="icon-"],p.titrecdt a[class^="icon-"],.maildest a[class^="icon-"]{padding-left:.3em}.avecform{border:none!important}h3.editable a[class^="icon-"],h3 span.editable a[class^="icon-"]{font-weight:500;font-size:.67em;padding-top:.1em}h3.avecform span{font-weight:500;font-size:.6em;margin-top:.5em;width:80%;overflow:hidden;white-space:nowrap}h3.avecform input{width:50%}textarea,[contenteditable=true].ligne{width:calc(100% - 3em);margin:0 1.5em}textarea+div{min-height:6em;border:1px dotted #CCC;background-color:#FFF}.boutons{clear:right;background-color:#DDD;border:1px solid #BBB;width:auto;padding:0;margin-bottom:0;border-radius:4px}.boutons button{cursor:default;background-color:transparent;border-top:0;border-left:none;border-bottom:1px solid #BBB;border-right:1px solid #BBB;height:1.5em;font-size:100%;width:2em}.boutons button+button{margin-left:-0.2em}p.boutons.ligne{width:96%;margin:0 2%}[contenteditable=true]:empty:before{content:attr(placeholder);color:#999;font-size:.8em;display:block}div.editable a[class^="icon-"]{position:absolute;right:3px;top:0}div.editable a.icon-annule{top:1.5em}div.edithtml a.icon-ok{top:1.6em}div.edithtml a.icon-annule{top:3.1em}.icon-mailenvoi{font-size:2em}#notes th,#notes td{padding:.15em .5em}#notes .icones{text-align:left;padding:.15em .5em;width:2.3em}.notes td+td{width:6em;text-align:center}.notes td+td select{width:6em;font-size:.8em;margin-bottom:.2em}.notes+p.ligne{clear:right;margin-top:.5em}td.pasnote{font-style:italic;text-align:center}.collsel{font-weight:700}.collnosel,.dejanote{color:#AAA}#tableaunotes td+td{text-align:right}.utilisateurs th,.utilisateurs td{border:1px dotted #BBB}.utilisateurs .icone{text-align:center;width:1.4em}#fenetre .utilisateurs .icone{width:5em;padding:0}.categorie th:first-child{padding-left:3%}.utilisateurs .icones{width:1em;white-space:nowrap;font-weight:normal;text-align:right}.utilisateurs .icones *{font-weight:normal;padding:0;margin:0}.utilisateurs .icones input{width:1em}.utilisateurs .icones a{display:inline-block;width:1em}.categorie span,#envoimails span{cursor:pointer}.utilisateurs .cache{padding:0 .3em}.utilisateurs .cache div{padding:.1em 0;width:100%}.utilisateurs .cache.icone div{text-align:center}#planning select{font-size:.8em;height:1.6em;margin-bottom:3px}th.vertical{vertical-align:bottom;padding:1em 0;text-align:center;min-width:1.4em}th.vertical span{display:inline-block;white-space:nowrap;writing-mode:vertical-lr;-webkit-writing-mode:vertical-rl;transform:rotate(180deg);-webkit-transform:rotate(180deg)}@media print{body{font-size:90%;font-family:Serif}#colonne,#recherchecolle,#recherchecdt,#rechercheagenda,[id^="aide-"],[id^="form-"],footer,a[class^="icon-"]{display:none}.editable,.titrecdt.edition,form.titrecdt{border:0}h1{font-size:1.7em}h2{font-size:1.5em;margin:.7em 0}h3{font-size:1.35em;margin:.6em 0}h4{font-size:1.2em;margin:.4em 0 .2em}article{border:1px solid #999}table th{padding:.15em .5%}}#calendrier{margin-top:1em}#calendrier table{table-layout:fixed}#semaine,.semaine-bg,.evenements{margin:0}#semaine{font-weight:900;text-align:center}#semaine th{overflow:hidden;text-overflow:clip}.semaine-bg{border-top:0;position:absolute;z-index:1}.autremois{background-color:#e7eefe;color:#002877}#aujourdhui{background-color:#99b3e5}.evenements{position:relative;z-index:2;border-top:0;border-bottom:0}.evenements thead{border-bottom:1px solid #999}.evenements th{padding:.15em .5%;text-align:right}.evenements td{padding:2px 3px 1px;border:none!important}.modifevnmt{padding:1px 3px;border-radius:5px;white-space:nowrap;overflow:hidden;font-size:.8em;cursor:pointer}.evnmt_suivi{border-top-right-radius:0;border-bottom-right-radius:0;margin-right:-2px}.evnmt_suite{border-top-left-radius:0;border-bottom-left-radius:0;margin-left:-3px}#load{display:none;margin:0;padding:0;position:fixed;top:0;left:0;width:100%;height:100%;z-index:30;text-align:center}#load img{position:absolute;top:50%}#cahiers{text-align:center}#cahiers a{text-decoration:none;font-weight:700;display:block;color:#000}#cahiers a:hover{color:#002877;background-color:#e7eefe}
\ No newline at end of file
diff -urN cahier-de-prepa8.1.1/def_sql.php cahier-de-prepa9.0.0/def_sql.php
--- cahier-de-prepa8.1.1/def_sql.php	2018-10-27 23:56:44.625458730 +0200
+++ cahier-de-prepa9.0.0/def_sql.php	2019-08-28 14:55:58.599311389 +0200
@@ -25,10 +25,10 @@
 -- colles, cdt, docs : 0 si vide, 1 si présent
 -- notes : 0 si vide, 1 si présent, 2 si désactivées
 -- *_protection : valeur numérique de gestion de la protection. Si nul, autorisation à tous, sans
---    nécessité de connexion identifiée. Si entre 1 et 32, conversion de la valeur binaire PACEI
---    (profs,administration,colleurs,élèves,invités) à laquelle on a ajouté 1. Chaque 0 correspond
+--    nécessité de connexion identifiée. Si entre 1 et 32, conversion de la valeur binaire PLCEI
+--    (profs,lycée,colleurs,élèves,invités) à laquelle on a ajouté 1. Chaque 0 correspond
 --    aux accès autorisés, chaque 1 correspond aux protections (accès interdit pour ce type de compte).
---    Exemple : 10->PACEI=9=01001->autorisé pour P,C,E et interdit pour A et I.
+--    Exemple : 10->PLCEI=9=01001->autorisé pour P,C,E et interdit pour L et I.
 --    Le code 32 (interdit pour tous) correspond aux fonctions désactivées et aux documents/répertoires
 --    non visibles : plus d'affichage dans le menu, plus d'accès.
 -- dureecolle : durée pour un élève, en minutes
@@ -51,7 +51,7 @@
   KEY `notes` (`notes`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
--- autorisation : type d'utilisateur (1:invité, 2:élève, 3:colleur, 4:administration, 5:professeur)
+-- autorisation : type d'utilisateur (1:invité, 2:élève, 3:colleur, 4:lycée, 5:professeur)
 -- mdp : stockage du mot de passe sur 40 caractères
 --       * si commence par un ? : invitation non répondue (mot de passe non défini)
 --       * si commence par un * : compte demandé en attente de validation
@@ -75,8 +75,6 @@
   `timeout` smallint(4) UNSIGNED NOT NULL,
   `mailexp` varchar(50) NOT NULL,
   `mailcopie` tinyint(1) UNSIGNED NOT NULL,
-  `mailenvoi` tinyint(1) UNSIGNED NOT NULL,
-  `mailliste` tinyint(1) UNSIGNED NOT NULL,
   `permconn` varchar(10) NOT NULL,
   `lastconn` datetime NOT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
@@ -113,6 +111,11 @@
   KEY `colle` (`colle`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
+CREATE TABLE `vacances` (
+  `id` tinyint(2) unsigned NOT NULL PRIMARY KEY,
+  `nom` varchar(50) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+
 CREATE TABLE `colles` (
   `id` tinyint(3) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
   `semaine` tinyint(2) unsigned NOT NULL,
@@ -203,15 +206,19 @@
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
 CREATE TABLE `recents` (
-  `id` smallint(5) unsigned NOT NULL PRIMARY KEY,
-  `heure` datetime NOT NULL,
+  `id` smallint(5) UNSIGNED NOT NULL,
+  `type` tinyint(1) UNSIGNED NOT NULL,
+  `publi` datetime NOT NULL,
+  `maj` datetime NOT NULL,
   `titre` varchar(200) NOT NULL,
   `lien` varchar(30) NOT NULL,
   `texte` text NOT NULL,
-  `protection` tinyint(1) unsigned NOT NULL,
-  `matiere` tinyint(2) unsigned NOT NULL,
-  KEY `heure` (`heure`)
-) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
+  `protection` tinyint(1) UNSIGNED NOT NULL,
+  `matiere` tinyint(2) UNSIGNED NOT NULL,
+  PRIMARY KEY (`id`,`type`),
+  KEY `publi` (`publi`),
+  KEY `maj` (`maj`)
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
 CREATE TABLE notes (
   `id` smallint(5) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
@@ -271,18 +278,17 @@
 
 CREATE TABLE `prefs` (
   `nom` varchar(50) NOT NULL,
-  `val` tinyint(2) unsigned NOT NULL
+  `val` smallint(3) unsigned NOT NULL
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
 INSERT INTO prefs (nom,val)
   VALUES ('creation_compte',1),
          ('nb_agenda_index',10),
-         ('protection_globale',0),
          ('protection_agenda',0),
-         ('envoi_mail_defaut',0);
+         ('autorisation_mails',61440);
 
-INSERT INTO utilisateurs (id,login,prenom,nom,mail,mdp,autorisation,matieres,timeout,mailexp,mailcopie,mailenvoi,mailliste)
-  VALUES (1, '$login', '$prenom', '$nom', '$mail', '?', 5, '0,1', 900, '$prenom $nom', 1, 1, 1);
+INSERT INTO utilisateurs (id,login,prenom,nom,mail,mdp,autorisation,matieres,timeout,mailexp,mailcopie)
+  VALUES (1, '$login', '$prenom', '$nom', '$mail', '?', 5, '0,1', 900, '$prenom $nom', 1);
 
 INSERT INTO matieres (id,ordre,cle,nom)
   VALUES (1, 1, '$cle_matiere', '$nom_matiere');
@@ -314,38 +320,49 @@
          (7, 8, 'Jour férié', 'fer', 'CC3333'),
          (8, 9, 'Vacances', 'vac', '66CC33');
 
-INSERT INTO semaines (debut) VALUES ('2018-09-03'),('2018-09-10'),('2018-09-17'),('2018-09-24'),
-  ('2018-10-01'),('2018-10-08'),('2018-10-15'),('2018-10-22'),('2018-10-29'),('2018-11-05'),('2018-11-12'),('2018-11-19'),('2018-11-26'),
-  ('2018-12-03'),('2018-12-10'),('2018-12-17'),('2018-12-24'),('2018-12-31'),('2019-01-07'),('2019-01-14'),('2019-01-21'),
-  ('2019-01-28'),('2019-02-04'),('2019-02-11'),('2019-02-18'),('2019-02-25'),('2019-03-04'),('2019-03-11'),('2019-03-18'),('2019-03-25'),
-  ('2019-04-02'),('2019-04-08'),('2019-04-15'),('2019-04-22'),('2019-04-29'),('2019-05-06'),('2019-05-13'),('2019-05-21'),('2019-05-27'),
-  ('2019-06-03'),('2019-06-10'),('2019-06-17'),('2019-06-24'),('2019-07-01');
-UPDATE semaines SET colle = 1;
-
-INSERT INTO agenda (id,matiere,debut,fin,type,texte)
-  VALUES 
-         (1, 0, '2018-09-03 00:00:00', '2018-09-03 00:00:00', 3, '<div class="annonce">C''est la rentrée ! Bon courage pour cette nouvelle année&nbsp;!</div>'),
-         (2, 0, '2018-08-15 00:00:00', '2018-08-15 00:00:00', 7, '<p>Assomption</p>'),
-         (3, 0, '2018-11-01 00:00:00', '2018-11-01 00:00:00', 7, '<p>Toussaint</p>'),
-         (4, 0, '2018-11-11 00:00:00', '2018-11-11 00:00:00', 7, '<p>Armistice 1918</p>'),
-         (5, 0, '2018-12-25 00:00:00', '2018-12-25 00:00:00', 7, '<p>Noël</p>'),
-         (6, 0, '2019-01-01 00:00:00', '2019-01-01 00:00:00', 7, '<p>Jour de l''an</p>'),
-         (7, 0, '2019-04-22 00:00:00', '2019-04-22 00:00:00', 7, '<p>Lundi de Pâques</p>'),
-         (8, 0, '2019-05-01 00:00:00', '2019-05-01 00:00:00', 7, '<p>Fête du travail</p>'),
-         (9, 0, '2019-05-08 00:00:00', '2019-05-08 00:00:00', 7, '<p>Armistice 1945</p>'),
-         (10, 0, '2019-05-30 00:00:00', '2019-05-30 00:00:00', 7, '<p>Jeudi de l''Ascension</p>'),
-         (11, 0, '2019-06-10 00:00:00', '2019-06-10 00:00:00', 7, '<p>Lundi de Pentecôte</p>'),
-         (12, 0, '2019-07-14 00:00:00', '2019-07-14 00:00:00', 7, '<p>Fête Nationale</p>'),
-         (13, 0, '2018-07-08 00:00:00', '2018-09-02 00:00:00', 8, '<p>Vacances d''été</p>'),
-         (14, 0, '2018-10-21 00:00:00', '2018-11-04 00:00:00', 8, '<p>Vacances de la Toussaint</p>'),
-         (15, 0, '2018-12-23 00:00:00', '2019-01-06 00:00:00', 8, '<p>Vacances de Noël</p>'),
-         (16, 0, '2019-02-17 00:00:00', '2019-03-03 00:00:00', 8, '<p>Vacances d''hiver, zone A</p>'),
-         (17, 0, '2019-02-10 00:00:00', '2019-02-24 00:00:00', 8, '<p>Vacances d''hiver, zone B</p>'),
-         (18, 0, '2019-02-24 00:00:00', '2019-03-10 00:00:00', 8, '<p>Vacances d''hiver, zone C</p>'),
-         (19, 0, '2019-04-14 00:00:00', '2019-04-28 00:00:00', 8, '<p>Vacances de printemps, zone A</p>'),
-         (20, 0, '2019-04-07 00:00:00', '2019-04-22 00:00:00', 8, '<p>Vacances de printemps, zone B</p>'),
-         (21, 0, '2019-04-21 00:00:00', '2019-05-05 00:00:00', 8, '<p>Vacances de printemps, zone C</p>'),
-         (22, 0, '2019-07-07 00:00:00', '2019-09-01 00:00:00', 8, '<p>Vacances d''été</p>');
+INSERT INTO semaines (id,debut) VALUES 
+   (1,'2019-09-02'), (2,'2019-09-09'), (3,'2019-09-16'), (4,'2019-09-23'), (5,'2019-09-30'),
+   (6,'2019-10-07'), (7,'2019-10-14'), (8,'2019-10-21'), (9,'2019-10-28'),(10,'2019-11-04'),
+  (11,'2019-11-11'),(12,'2019-11-18'),(13,'2019-11-25'),(14,'2019-12-02'),(15,'2019-12-09'),
+  (16,'2019-12-16'),(17,'2019-12-23'),(18,'2019-12-30'),(19,'2020-01-06'),(20,'2020-01-13'),
+  (21,'2020-01-20'),(22,'2020-01-27'),(23,'2020-02-03'),(24,'2020-02-10'),(25,'2020-02-17'),
+  (26,'2020-02-24'),(27,'2020-03-02'),(28,'2020-03-09'),(29,'2020-03-16'),(30,'2020-03-23'),
+  (31,'2020-03-30'),(32,'2020-04-06'),(33,'2020-04-13'),(34,'2020-04-20'),(35,'2020-04-27'),
+  (36,'2020-05-04'),(37,'2020-05-11'),(38,'2020-05-18'),(39,'2020-05-25'),(40,'2020-06-01'),
+  (41,'2020-06-08'),(42,'2020-06-15'),(43,'2020-06-22'),(44,'2020-06-29');
+
+INSERT INTO vacances (id, nom) VALUES
+  (0, ''),
+  (1, 'Vacances de la Toussaint'),
+  (2, 'Vacances de Noël'),
+  (3, "Vacances d'hiver"),
+  (4, 'Vacances de printemps');
+
+-- Planning de la zone C
+UPDATE semaines SET vacances = 1 WHERE id = 8 OR id = 9;
+UPDATE semaines SET vacances = 2 WHERE id = 17 OR id = 18;
+UPDATE semaines SET vacances = 3 WHERE id = 24 OR id = 25;
+UPDATE semaines SET vacances = 4 WHERE id = 32 OR id = 33;
+UPDATE semaines SET colle = 1 WHERE vacances = 0;  
+
+INSERT INTO agenda (id,matiere,debut,fin,type,texte) VALUES 
+  ( 1, 0, '2019-09-02 00:00:00', '2019-09-02 00:00:00', 3, '<div class="annonce">C''est la rentrée ! Bon courage pour cette nouvelle année&nbsp;!</div>'),
+  ( 2, 0, '2019-11-01 00:00:00', '2019-11-01 00:00:00', 7, '<p>Toussaint</p>'),
+  ( 3, 0, '2019-11-11 00:00:00', '2019-11-11 00:00:00', 7, '<p>Armistice 1918</p>'),
+  ( 4, 0, '2019-12-25 00:00:00', '2019-12-25 00:00:00', 7, '<p>Noël</p>'),
+  ( 5, 0, '2020-01-01 00:00:00', '2020-01-01 00:00:00', 7, '<p>Jour de l''an</p>'),
+  ( 6, 0, '2020-04-13 00:00:00', '2020-04-13 00:00:00', 7, '<p>Lundi de Pâques</p>'),
+  ( 7, 0, '2020-05-01 00:00:00', '2020-05-01 00:00:00', 7, '<p>Fête du travail</p>'),
+  ( 8, 0, '2020-05-08 00:00:00', '2020-05-08 00:00:00', 7, '<p>Armistice 1945</p>'),
+  ( 9, 0, '2020-05-21 00:00:00', '2020-05-24 00:00:00', 7, '<p>Pont de l''Ascension</p>'),
+  (10, 0, '2020-06-01 00:00:00', '2020-06-01 00:00:00', 7, '<p>Lundi de Pentecôte</p>'),
+  (11, 0, '2020-07-14 00:00:00', '2020-07-14 00:00:00', 7, '<p>Fête Nationale</p>'),
+  (12, 0, '2019-07-07 00:00:00', '2019-09-01 00:00:00', 8, '<p>Vacances d''été</p>'),
+  (13, 0, '2019-10-20 00:00:00', '2019-11-03 00:00:00', 8, '<p>Vacances de la Toussaint</p>'),
+  (14, 0, '2019-12-22 00:00:00', '2020-01-05 00:00:00', 8, '<p>Vacances de Noël</p>'),
+  (15, 0, '2020-02-09 00:00:00', '2020-02-23 00:00:00', 8, '<p>Vacances d''hiver</p>'),
+  (16, 0, '2020-04-05 00:00:00', '2020-04-19 00:00:00', 8, '<p>Vacances de printemps</p>'),
+  (17, 0, '2020-07-05 00:00:00', '2020-09-01 00:00:00', 8, '<p>Vacances d''été</p>');
 
 FIN;
 ?>
diff -urN cahier-de-prepa8.1.1/docs.php cahier-de-prepa9.0.0/docs.php
--- cahier-de-prepa8.1.1/docs.php	2018-10-20 02:07:05.197718005 +0200
+++ cahier-de-prepa9.0.0/docs.php	2019-08-26 01:35:41.328219964 +0200
@@ -99,10 +99,13 @@
   'mp3' => '-mp3', 'ogg' => '-mp3', 'oga' => '-mp3', 'wma' => '-mp3', 'wav' => '-mp3', 'ra' => '-mp3', 'rm' => '-mp3',
   'mp4' => '-mp4', 'avi' => '-mp4', 'mpeg' => '-mp4', 'mpg' => '-mp4', 'wmv' => '-mp4', 'mp4' => '-mp4', 'ogv' => '-mp4', 'qt' => '-mp4', 'mov' => '-mp4', 'mkv' => '-mp4', 'flv' => '-mp4',
   'zip' => '-zip', 'rar' => '-zip', '7z' => '-zip',
-  'py' => '-pyt', 'exe' => '-pyt', 'sh' => '-pyt', 'ml' => '-pyt', 'mw' => '-pyt',
-  'txt' => '-txt', 'rtf' => '-txt', '' => '-txt'
+  'py' => '-py', 'exe' => '-py', 'sh' => '-py', 'ml' => '-py', 'mw' => '-py',
+  'db' => '-db', 'db3' => '-db', 'sqlite' => '-db',
+  'sql' => '-sql',
+  'txt' => '', 'rtf' => '', '' => ''
 );
 
+
 // Affichage public sans édition
 if ( !$edition )  {
   echo <<< FIN
@@ -292,7 +295,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Administratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Répertoire invisible</option>';
   // Protection des nouveaux répertoires = protection globale du répertoire
@@ -321,7 +324,7 @@
       <select name="protection[]" multiple><?php echo $select_protection; ?>
       </select>
     </p>
-    <input type="button" class="ligne" value="Propager le choix d'accès à chaque document/sous-répertoire">
+    <p class="ligne"><label for="menu">Propager ce choix d'accès à chaque document/sous-répertoire&nbsp;: </label><input type="checkbox" name="propage" value="1"></p>
     <input type="button" class="ligne" value="Vider ce répertoire">
   </form>
 
@@ -339,6 +342,7 @@
     <h3 class="edition">Modifier le document <em></em></h3>
     <p class="ligne"><label for="nom">Nom&nbsp;: </label><input type="text" name="nom" value="" size="50"></p>
     <p class="ligne"><label for="fichier">Mettre à jour&nbsp;: </label><input type="file" name="fichier"></p>
+    <p class="ligne"><label for="publi">Publier en tant que mise à jour&nbsp;: </label><input type="checkbox" name="publi" value="1" checked></p>
     <p class="ligne"><label for="parent">Déplacer&nbsp;: </label>
       <select name="parent">
         <option value="0">Ne pas déplacer</option><?php echo str_replace("\"$rid\"","\"$rid\" disabled",$select_reps); ?>
diff -urN cahier-de-prepa8.1.1/fonctions.php cahier-de-prepa9.0.0/fonctions.php
--- cahier-de-prepa8.1.1/fonctions.php	2018-11-11 00:24:48.449894371 +0100
+++ cahier-de-prepa9.0.0/fonctions.php	2019-08-29 00:19:30.432125603 +0200
@@ -7,68 +7,115 @@
 ////////////////////////////////////////////////////////////////////////////////
 
 // Fonction de connexion à la base MySQL
-function connectsql($ecriture=false)  {
-  $mysqli = new mysqli($GLOBALS['serveur'],( $ecriture ) ? $GLOBALS['base'].'-adm' : $GLOBALS['base'], $GLOBALS['mdp'], $GLOBALS['base']);
+// $interfaceglobale permet d'écrire dans la base de données globales, pour les
+// mises à jour d'adresse électronique/mot de passe, si configuré dans config.php.
+function connectsql($ecriture=false,$interfaceglobale=false)  {
+  if ( $interfaceglobale )  {
+    // Le include est dans une fonction pour éviter la réécriture des variables
+    include("${interfaceglobale}config.php");
+    $mysqli = new mysqli($serveur,( $ecriture ) ? $base.'-adm' : $base, $mdp, $base);
+  }
+  else
+    $mysqli = new mysqli($GLOBALS['serveur'],( $ecriture ) ? $GLOBALS['base'].'-adm' : $GLOBALS['base'], $GLOBALS['mdp'], $GLOBALS['base']);
   $mysqli->set_charset('utf8');
   return $mysqli;
 }
 
-// Fonction d'écriture des connexion
+// Fonction d'écriture des connexions
 // $connexion = 1 pour connexion normale, 2 pour connexion light par cookie,
-//              3 pour déconnexion, 4 pour reconnexion light, 5 pour
-//              reconnexion normale
-function logconnect($connexion,$login)  {
+//              3 pour reconnexion normale, 4 pour reconnexion light, 5 pour déconnexion
+function logconnect($connexion)  {
   if ( is_dir('sauvegarde') && is_executable('sauvegarde') && is_writable('sauvegarde') )  {
-    $mois = date('Y-m');
-    if ( !file_exists("sauvegarde/connexion.$mois.php") )  {
-      $fichier = fopen("sauvegarde/connexion.$mois.php",'wb');
-      fwrite($fichier, "<?php exit(); ?>\n\n");
+    if ( !file_exists($fichier = 'sauvegarde/connexion.'.date('Y-m').'php') )  {
+      $f = fopen($fichier,'wb');
+      fwrite($f, "<?php exit(); ?>\n\n");
     }
     else
-      $fichier = fopen("sauvegarde/connexion.$mois.php",'ab');
+      $f = fopen($fichier,'ab');
     switch ( $connexion )  {
-      case 1: fwrite($fichier, 'Le '.date('d/m/Y à H:i:s').", connexion de $login\n"); break;
-      case 2: fwrite($fichier, 'Le '.date('d/m/Y à H:i:s').", connexion light par cookie de $login\n"); break;
-      case 3: fwrite($fichier, 'Le '.date('d/m/Y à H:i:s').", déconnexion de $login\n"); break;
-      case 4: fwrite($fichier, 'Le '.date('d/m/Y à H:i:s').", reconnexion light de $login\n"); break;
-      case 5: fwrite($fichier, 'Le '.date('d/m/Y à H:i:s').", reconnexion normale de $login\n"); break;
-    }
-    fclose($fichier);
+      case 1: fwrite($f, 'Le '.date('d/m/Y à H:i:s').", connexion de ${_SESSION['login']}\n"); break;
+      case 2: fwrite($f, 'Le '.date('d/m/Y à H:i:s').", connexion light par cookie de ${_SESSION['login']}\n"); break;
+      case 3: fwrite($f, 'Le '.date('d/m/Y à H:i:s').", reconnexion normale de ${_SESSION['login']}\n"); break;
+      case 4: fwrite($f, 'Le '.date('d/m/Y à H:i:s').", reconnexion light de ${_SESSION['login']}\n"); break;
+      case 5: fwrite($f, 'Le '.date('d/m/Y à H:i:s').", déconnexion de ${_SESSION['login']}\n"); break;
+    }
+    fclose($f);
   }
 }
 
-// Fonction de remplissage de la variable $_SESSION
-// Le paramètre $light est true si la connexion est obtenue par cookie,
-// et ne sert donc qu'à la lecture
-// Cette fonction sert dans ajax.php et fonctions.php
-function enregistre_session($r,$light=true)  {
-  // Interdiction de garder son identifiant de session
+// Fonction d'enregistrement de session : remplissage de la variable $_SESSION et log
+// $r contient les données de l'utilisateur pour une nouvelle session, ou false
+// pour une simple mise à jour de $_SESSION['light'], $_SESSION['timeout'] et $_SESSION['time']
+// $light : true si la connexion est obtenue par cookie et ne permet que la lecture
+// $timeout : utile dans le cas du passage de connexion normale à connexion light uniquement
+// Cette fonction est utilisée uniquement dans ajax.php et fonctions.php
+function enregistre_session($r,$light,$timeout=0)  {
+  // Nouvelle session
+  if ( $r )  {
+    // Interdiction de garder son identifiant de session
+    session_regenerate_id(true);
+    $_SESSION = array();
+    // Interdiction de pouvoir se connecter aux autres site sur le même serveur
+    $_SESSION['chemin'] = $GLOBALS['chemin'];
+    // Pour vérification aux connexions ultérieures
+    $_SESSION['client'] = $_SERVER['HTTP_USER_AGENT'];
+    $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
+    $_SESSION['login'] = $r['login'];
+    $_SESSION['id'] = $r['id'];
+    $_SESSION['permconn'] = $r['permconn'];
+    $_SESSION['lastconn'] = $r['lastconn'];
+    // Mise à jour de dernière connexion
+    $mysqli = connectsql(true);
+    $mysqli->query("UPDATE utilisateurs SET lastconn = NOW() WHERE id = ${r['id']}");
+    $mysqli->close();
+    // Autorisations
+    $_SESSION['light'] = $light;
+    $_SESSION['autorisation'] = $r['autorisation'];
+    $_SESSION['matieres'] = $r['matieres'];
+    // Temps de session : depuis la base si connexion normale, 1 jour si light
+    $_SESSION['timeout'] = ( $light ) ? 86400 : ( $r['timeout']?:900 );
+    $_SESSION['time'] = time() + $_SESSION['timeout'];
+    // Pour sécurisation des requêtes AJAX
+    $_SESSION['csrf-token'] = $_REQUEST['csrf-token'] ?? bin2hex(random_bytes(32));
+    // Si interface globale, vérification
+    $_SESSION['compteglobal'] = false;
+    if ( ( $r['autorisation'] > 1 ) && $GLOBALS['interfaceglobale'] )  {
+      $mysqli = connectsql(false,$GLOBALS['interfaceglobale']);
+      // Identifiant global de l'utilisateur = 1000*idCahier+idUtilisateur
+      // On cherche uniquement un compte correspondant à au moins deux connexions
+      $resultat = $mysqli->query("SELECT id FROM comptes 
+                                  WHERE FIND_IN_SET( (SELECT id FROM cahiers WHERE rep = TRIM(BOTH '/' FROM '${GLOBALS['chemin']}'))*1000+${r['id']}, connexions) AND LOCATE(',',connexions)");
+      if ( $resultat->num_rows )  {
+        $_SESSION['compteglobal'] = $resultat->fetch_row()[0];
+        $resultat->free();
+      }
+      $mysqli->close();
+    }
+  }
+  // Mise à jour de session
+  else  {
+    $_SESSION['light'] = $light;
+    $_SESSION['timeout'] = ( $light ) ? 86400 : ( $timeout?:900 );
+    $_SESSION['time'] = time() + $_SESSION['timeout'];
+  }
+  // Écriture de la connexion dans le fichier de log (voir commentaires de logconnect)
+  logconnect(1+$light+2*!$r);
+}
+
+// Fonction de suppression de session
+// Cette fonction est utilisée uniquement dans ajax.php et fonctions.php
+function suppression_session()  {
+  // Écriture de la déconnexion dans le fichier de log, sauf si la session a
+  // été perdue parce qu'effacée du serveur
+  if ( isset($_SESSION['login']) )  {
+    logconnect(5);
+    // Suppression des données de session et de l'éventuel cookie de connexion permanente
+    $_SESSION = array();
+    setcookie('CDP_SESSION_PERM','',time()-3600,$GLOBALS['chemin'],$GLOBALS['domaine'],true);
+  }
+  // Suppression du cookie de session et régénération interne de l'identifiant de session
+  setcookie('CDP_SESSION','',time()-3600,$GLOBALS['chemin'],$GLOBALS['domaine'],true);
   session_regenerate_id(true);
-  $_SESSION = array();
-  // Interdiction de pouvoir se connecter aux autres site sur le même serveur
-  $_SESSION[md5($GLOBALS['site'])] = true;
-  // Pour vérification aux connexions ultérieures
-  $_SESSION['client'] = $_SERVER['HTTP_USER_AGENT'];
-  $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
-  $_SESSION['login'] = $r['login'];
-  $_SESSION['id'] = $r['id'];
-  $_SESSION['permconn'] = $r['permconn'];
-  $_SESSION['lastconn'] = $r['lastconn'];
-  // Mise à jour de dernière connexion
-  $mysqli = connectsql(true);
-  $mysqli->query("UPDATE utilisateurs SET lastconn = NOW() WHERE id = ${r['id']}");
-  // Autorisations
-  $_SESSION['light'] = $light;
-  $_SESSION['autorisation'] = $r['autorisation'];
-  $_SESSION['mailenvoi'] = $r['mailenvoi'];
-  $_SESSION['matieres'] = $r['matieres'];
-  // Temps de session
-  $_SESSION['timeout'] = $r['timeout'];
-  $_SESSION['time'] = ( $_SESSION['timeout'] == 0 ) ? time()+900 : time()+$_SESSION['timeout'];
-  // Écriture de la connexion dans le fichier de log
-  logconnect(1+$light,$r['login']);
-  // Pour sécurisation des requêtes AJAX
-  $_SESSION['csrf-token'] = ( isset($_REQUEST['csrf-token']) ) ? $_REQUEST['csrf-token'] : bin2hex(random_bytes(32));
 }
 
 // Fonction de vérification de la qualité light ou non de la connexion
@@ -83,44 +130,33 @@
 }
 
 // Création de session
-session_name(md5($site));
-session_set_cookie_params(0,strchr($site,'/').'/',str_replace(strchr($site,'/'),'',$site),true);
+session_name('CDP_SESSION');
+session_set_cookie_params(0,$chemin,$domaine,true);
 session_start();
 // Niveau d'autorisation
 //  * 0 = non connecté
 //  * 1 = compte invité
 //  * 2 = élève
 //  * 3 = colleur
-//  * 4 = administration
+//  * 4 = lycée
 //  * 5 = professeur
 // Gestion des protections : voir la fonction acces ci-dessous
 $message = '';
 // Gestion des utilisateurs connectés
-if ( isset($_SESSION[md5("$site")]) )  {
+if ( isset($_SESSION['chemin']) && ( $_SESSION['chemin'] == $chemin ) )  {
   // Passage en connexion light si timeout mais connexion permanente
-  if ( ( $_SESSION['time'] < time() ) && !$_SESSION['light'] && $_SESSION['permconn'] )  {
-    $_SESSION['light'] = true;
-    // Écriture de la connexion dans le fichier de log
-    logconnect(4,$_SESSION['login']);
-    // Mise à jour du timeout : une session est conservée moins d'un jour sur le serveur
-    $_SESSION['timeout'] = 86400;
-    $_SESSION['time'] = time()+86400;
-  }
+  if ( ( $_SESSION['time'] < time() ) && !$_SESSION['light'] && $_SESSION['permconn'] )
+    enregistre_session(false,true);
   // Passage en connexion normale si reconnexion sur une connexion light
   elseif ( $_SESSION['light'] && isset($_REQUEST['motdepasse']) )  {
     $mysqli = connectsql();
-    // Récupération des logins/mdp dans la base MySQL et comparaison
-    $resultat = $mysqli->query('SELECT timeout FROM utilisateurs WHERE ( mdp = \''.sha1($mdp.$_REQUEST['motdepasse']).'\' OR mdp = \''.sha1($_REQUEST['motdepasse'])."' ) AND id = ${_SESSION['id']}");
+    // Récupération du compte dans la base de données
+    $resultat = $mysqli->query('SELECT timeout FROM utilisateurs WHERE mdp = \''.sha1($mdp.$_REQUEST['motdepasse'])."' AND id = ${_SESSION['id']}");
     $mysqli->close();
     if ( $resultat->num_rows )  {
       $r = $resultat->fetch_row();
       $resultat->free();
-      $_SESSION['light'] = false;
-      // Écriture de la connexion dans le fichier de log
-      logconnect(5,$_SESSION['login']);
-      // Mise à jour du timeout
-      $_SESSION['timeout'] = $r[0];
-      $_SESSION['time'] = ( $_SESSION['timeout'] == 0 ) ? time()+900 : time()+$_SESSION['timeout'];
+      enregistre_session(false,false,$r[0]);
       // Si paramètre "connexion", reconnexion sans autre demande (par login.php),
       // suivie d'un rechargement immédiat : terminaison et $_SESSION['message']
       if ( isset($_REQUEST['connexion']) )
@@ -133,88 +169,74 @@
   // Changement d'IP: on ne regarde pas le dernier élément, certains lycées
   // on des adresses dynamiques à ce niveau
   elseif ( ( $_SESSION['time'] < time() ) || ( $_SESSION['client'] != $_SERVER['HTTP_USER_AGENT'] ) || ( substr($_SESSION['ip'],0,-3) != substr($_SERVER['REMOTE_ADDR'],0,-3) ) )  {
-    // Écriture de la déconnexion dans le fichier de log
-    logconnect(3,$_SESSION['login']);
-    // Suppression du cookie et des données de session
-    $_SESSION = array();
-    setcookie(session_name(),'',time()-3600);
-    setcookie('loginpermanent','',time()-3600);
-    session_regenerate_id(true);
-    // Si déconnexion demandée, pas la peine d'aller plus loin (venant de ajax.php)
-    //~ if ( isset($_REQUEST['action']) && ( $_REQUEST['action'] == 'deconnexion' ) )
-      //~ exit($_SESSION['message'] = '{"etat":"ok","message":"Déconnexion réussie"}');
+    suppression_session();
+    // Pour la suite du script
     $message = 'Vous devez vous connecter à nouveau, suite à une longue durée d\'inactivité.';
     $_SESSION['autorisation'] = 0;
   }
   // Tout est ok : session valide pendant timeout
   else
-    $_SESSION['time'] = ( $_SESSION['timeout'] == 0 ) ? time()+900 : time()+$_SESSION['timeout'];
+    $_SESSION['time'] = time() + $_SESSION['timeout'];
 }
-else  {
+// Connexion complète (login et mdp, script ajax.php demandé)
+elseif ( isset($_REQUEST['motdepasse']) && isset($_REQUEST['login']) && strlen($login = trim($_REQUEST['login'])) )  {
   // Pas de connexion a priori
   $_SESSION['autorisation'] = 0;
-  // Connexion complète (login et mdp, script ajax.php demandé)
-  if ( isset($_REQUEST['motdepasse']) && isset($_REQUEST['login']) )  {
-    $mysqli = connectsql();
-    // Récupération des logins/mdp dans la base MySQL et comparaison
-    $resultat = $mysqli->query('SELECT id, login, mdp, autorisation, matieres, timeout, mailenvoi, permconn, lastconn FROM utilisateurs WHERE mdp = \''.sha1($mdp.$_REQUEST['motdepasse']).'\' OR mdp = \''.sha1($_REQUEST['motdepasse']).'\'');
-    $mysqli->close();
-    while ( $r = $resultat->fetch_assoc() )
-      if ( $r['login'] == $_REQUEST['login'] )  {
-        enregistre_session($r,false);
-        // Modification interne du stockage du mot de passe -- mesure temporaire
-        if ( $r['mdp'] == sha1($_REQUEST['motdepasse']) )  {
-          $mysqli = connectsql(true);
-          $mysqli->query('UPDATE utilisateurs SET mdp = \''.sha1($mdp.$_REQUEST['motdepasse'])."' WHERE id = ${r['id']}");
-          $mysqli->close();
-        }
-        // Écriture du cookie pour connexion light
-        if ( $_SESSION['permconn'] )
-          setcookie('loginpermanent',$r['permconn'],time()+31536000);
-        break;
-      }
-    $resultat->free();
-    if ( $_SESSION['autorisation'] == 0 )  {
-      if ( filter_var($_REQUEST['login'],FILTER_VALIDATE_EMAIL) )
-        exit('{"etat":"nok","message":"Mauvais couple identifiant/mot de passe. L\'identifiant n\'est pas une adresse électronique."}');
-      exit('{"etat":"nok","message":"Mauvais couple identifiant/mot de passe"}');
-    }
-    // Si paramètre "connexion", connexion initiale (bouton "connexion" ou login.php),
-    // suivie d'un rechargement immédiat : terminaison et $_SESSION['message']
-    if ( isset($_REQUEST['connexion']) )  {
-      if ( isset($_REQUEST['permconn']) )  {
-        // Token de connexion automatique
+  // Récupération du compte dans la base de données
+  $mysqli = connectsql();
+  $resultat = $mysqli->query('SELECT * FROM utilisateurs WHERE mdp = \''.sha1($mdp.$_REQUEST['motdepasse']).'\'');
+  while ( $r = $resultat->fetch_assoc() )
+    if ( ( $r['login'] == $_REQUEST['login'] ) || ( $r['mail'] == $_REQUEST['login'] ) )  {
+      // Pas de connexion permanente si ce n'est pas coché (mais on ne modifie pas la
+      // base : on ne supprime pas celles qui pourraient exister sur d'autres appareils)
+      if ( !isset($_REQUEST['permconn']) )
+        $r['permconn'] = '';
+      // Génération du token de connexion automatique si demandé et s'il n'existe pas déjà
+      elseif ( !strlen($r['permconn']) )  {
         $permconn = '';
-        if ( !strlen($permconn) && isset($_REQUEST['permconn']) )
-          for ( $i = 0; $i < 10; $i++ )
-            $permconn .= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[random_int(0,61)];
-        $mysqli = connectsql(true);
-        $mysqli->query("UPDATE utilisateurs SET permconn = '$permconn' WHERE id = ${r['id']}");
-        $mysqli->close();
-        $_SESSION['permconn'] = $permconn;
-        setcookie('loginpermanent',$permconn,time()+31536000);
+        for ( $i = 0; $i < 10; $i++ )
+          $permconn .= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[random_int(0,61)];
+        $mysqli2 = connectsql(true);
+        $mysqli2->query("UPDATE utilisateurs SET permconn = '$permconn' WHERE id = ${r['id']}");
+        $mysqli2->close();
+        $r['permconn'] = $permconn;
       }
-      exit($_SESSION['message'] = '{"etat":"ok","message":"Connexion réussie"}');
-    }
-  }
-  // Connexion light automatique par cookie
-  elseif ( isset($_COOKIE['loginpermanent']) && preg_match('/^\w{10}$/',$_COOKIE['loginpermanent']) )  {
-    $mysqli = connectsql();
-    // Récupération des logins/mdp dans la base MySQL et comparaison
-    $resultat = $mysqli->query("SELECT id, login, autorisation, matieres, timeout, mailenvoi, permconn, lastconn FROM utilisateurs WHERE mdp > '0' AND permconn = '${_COOKIE['loginpermanent']}'");
-    $mysqli->close();
-    if ( $resultat->num_rows )  {
-      enregistre_session($resultat->fetch_assoc(),true);
-      $_SESSION['timeout'] = 86400;
-      $_SESSION['time'] = time()+86400;
-      $resultat->free();
+      // Enregistrement de la session et écriture du cookie pour connexion light
+      enregistre_session($r,false);
+      if ( $r['permconn'] )
+        setcookie('CDP_SESSION_PERM',$r['permconn'],time()+31536000,$chemin,$domaine,true);
+      // Nombre d'éléments récents à afficher
+      $resultat = $mysqli->query("SELECT COUNT(id) FROM recents WHERE publi > '${r['lastconn']}' OR maj > '${r['lastconn']}'");
+      $_SESSION['recents'] = $resultat->fetch_row()[0];
+      break;
     }
-    // Suppression du cookie s'il ne correspond pas à un compte
-    else 
-      setcookie('loginpermanent','',time()-3600);
+  $resultat->free();
+  $mysqli->close();
+  if ( $_SESSION['autorisation'] == 0 )
+    exit('{"etat":"nok","message":"Mauvais couple identifiant/mot de passe"}');
+  // Si paramètre "connexion", connexion initiale (bouton "connexion" ou login.php),
+  // suivie d'un rechargement immédiat : terminaison et $_SESSION['message']
+  if ( isset($_REQUEST['connexion']) )
+    exit($_SESSION['message'] = '{"etat":"ok","message":"Connexion réussie"}');
+}
+// Connexion light automatique par cookie
+elseif ( isset($_COOKIE['CDP_SESSION_PERM']) && preg_match('/^\w{10}$/',$_COOKIE['CDP_SESSION_PERM']) )  {
+  $mysqli = connectsql();
+  // Récupération du compte dans la base de données
+  $resultat = $mysqli->query("SELECT * FROM utilisateurs WHERE mdp > '0' AND permconn = '${_COOKIE['CDP_SESSION_PERM']}'");
+  $mysqli->close();
+  if ( $resultat->num_rows )  {
+    enregistre_session($resultat->fetch_assoc(),true);
+    $resultat->free();
   }
-}
-$autorisation = $_SESSION['autorisation'];
+  // Suppression du cookie s'il ne correspond pas à un compte
+  else 
+    setcookie('CDP_SESSION_PERM','',time()-3600,$chemin,$domaine,true);
+}
+$autorisation = $_SESSION['autorisation'] ?? 0;
+// Destruction du cookie de session si non connecté
+if ( !$autorisation )
+  setcookie('CDP_SESSION','',time()-3600,$chemin,$domaine,true);
 
 ////////////////////////////////////////////////////////////////////////////////
 ////////////////////// Mise à jour de la base de données ///////////////////////
@@ -273,111 +295,110 @@
 }
 
 // Fonction de mise à jour des informations récentes
-function recent($mysqli,$type,$id,$matiere,$prop=array(),$ext='')  {
-  // $type : 1->informations, 2->programmes de colles, 3->documents, 5->agenda
-  // $id : celui de l'information/le programme de colles/le document/l'événement
-  // $matiere : id de la matière concernée (ou 0) pour savoir quel flux modifier
-  // $prop : contient titre (sans icône), lien, texte, matiere, protection
-  //         incomplet si mise à jour
-  //         vide si suppression de l'information récente
-  // $ext : ne sert que pour les documents, pour connaître l'icône à mettre
+// $type : 1->informations, 2->programmes de colles, 3->documents, 4->agenda
+// $id : celui de l'information/le programme de colles/le document/l'événement
+// $prop : tableau qui contient matiere (ou 0), titre, lien, texte, protection
+//         complet si ajout dans la base, incomplet si mise à jour
+//         les chaines titre, lien et texte doivent être échappées
+// $publi : true si publication de la date, pour les modifications (champ maj)
+function recent($mysqli,$type,$id,$prop=array(),$publi=true)  {
 
   // Ajout dans la base de données
-  if ( count($prop) == 5 )  {
-    switch ( $type )  {
-      case 1: $icone = '<span class="icon-infos"></span>'; break;
-      case 2: $icone = '<span class="icon-colles"></span>'; break;
-      case 3:
-        // Liste des icônes pour affichage
-        $icones = array(
-          '.pdf' => 'pdf',
-          '.doc' => 'doc', '.odt' => 'doc', '.docx' => 'doc',
-          '.xls' => 'xls', '.ods' => 'xls', '.xlsx' => 'xls',
-          '.ppt' => 'ppt', '.odp' => 'ppt', '.pptx' => 'ppt',
-          '.jpg' => 'jpg', '.jpeg' => 'jpg', '.png' => 'jpg', '.gif' => 'jpg', '.svg' => 'jpg', '.tif' => 'jpg', '.tiff' => 'jpg', '.bmp' => 'jpg', '.ps' => 'jpg', '.eps' => 'jpg',
-          '.mp3' => 'mp3', '.ogg' => 'mp3', '.oga' => 'mp3', '.wma' => 'mp3', '.wav' => 'mp3', '.ra' => 'mp3', '.rm' => 'mp3',
-          '.mp4' => 'mp4', '.avi' => 'mp4', '.mpeg' => 'mp4', '.mpg' => 'mp4', '.wmv' => 'mp4', '.mp4' => 'mp4', '.ogv' => 'mp4', '.qt' => 'mp4', '.mov' => 'mp4', '.mkv' => 'mp4', '.flv' => 'mp4',
-          '.zip' => 'zip', '.rar' => 'zip', '.7z' => 'zip',
-          '.py' => 'pyt', '.exe' => 'pyt', '.sh' => 'pyt', '.ml' => 'pyt', '.mw' => 'pyt',
-          '.txt' => 'txt', '.rtf' => 'txt', '' => 'txt'
-        );
-        $icone = '<span class="icon-doc-'.(( isset($icones[strtolower($ext)]) ) ? $icones[strtolower($ext)] : 'txt').'"></span>'; break;
-      case 5:
-        $icone = '<span class="icon-agenda"></span>';
-        // Suppression avant insertion, pour une mise à jour
-        requete('recents','DELETE FROM recents WHERE id = '.($type*1000+$id),$mysqli);
-    }
-    requete('recents',"INSERT INTO recents SET id=".($type*1000+$id).", heure = NOW(), titre = '$icone ${prop['titre']}', lien = '${prop['lien']}', texte = '${prop['texte']}', matiere = '${prop['matiere']}', protection = '${prop['protection']}'",$mysqli);
-  }
+  if ( count($prop) == 5 )
+    requete('recents',"INSERT INTO recents SET id=$id, type=$type, publi = NOW(), matiere = '${prop['matiere']}', titre = '${prop['titre']}', lien = '${prop['lien']}', texte = '${prop['texte']}', protection = '${prop['protection']}'",$mysqli);
   // Suppression de la base
-  elseif ( empty($prop) )  {
-    requete('recents','DELETE FROM recents WHERE id = '.($type*1000+$id),$mysqli);
+  elseif ( !$prop )  {
+    // Récupération des anciennes propriétés ; rien à faire si n'existe pas
+    $resultat = $mysqli->query("SELECT matiere, protection FROM recents WHERE id = $id AND type = $type");
+    if ( !$resultat->num_rows )
+      return true;
+    $prop = $resultat->fetch_assoc();
+    $resultat->free();
+    requete('recents',"DELETE FROM recents WHERE id = $id AND type = $type",$mysqli);
   }
   // Modification
   else  {
-    switch ( $type )  {
-      case 1:
-        // Modification du titre : pas de changement de date de l'info récente
-        if ( isset($prop['titre']) )
-          $requete = "titre = '<span class=\"icon-infos\"></span> ${prop['titre']}'";
-        // Modification de texte : mise en valeur dans les flux RSS
-        elseif ( isset($prop['texte']) )
-          $requete = "heure = NOW(), texte = '${prop['texte']}', titre = CONCAT(REPLACE(titre,' (mise à jour)',''),' (mise à jour)')";
-        // Modification de la protection : pas de changement de date de l'info récente
-        elseif ( isset($prop['protection']) )
-          $requete = "protection = ${prop['protection']}";
-      break;
-      case 2:
-        // Modification de texte uniquement
-        $requete = "heure = NOW(), texte = '${prop['texte']}', titre = CONCAT(REPLACE(titre,' (mise à jour)',''),' (mise à jour)')";
-      break;
-      break;
-      case 3:
-        // Nouveau nom de document : mise à jour du titre et du texte seulement
-        if ( isset($prop['nom']) )
-          $requete = "titre = REPLACE(REPLACE(CONCAT(titre,'¤'),'/${prop['ancien_nom']}¤','/${prop['nom']}¤'),'¤',''), texte = REPLACE(texte,'/${prop['ancien_nom']}</a>','/${prop['nom']}</a>')";
-        // Déplacement de répertoire : mise à jour du chemin et peut-être de la
-        // matière. Pas de mise en valeur dans les flux RSS
-        elseif ( isset($prop['chemin']) )
-          $requete = "texte = REPLACE(texte,SUBSTRING(titre,36),'${prop['chemin']}'), titre = CONCAT(SUBSTRING(titre,1,35),'${prop['chemin']}'), matiere = '${prop['matiere']}'";
-        elseif ( isset($prop['maj']) )
-          $requete = 'heure = NOW(), texte = REPLACE(texte,\'<p>Nouveau \',\'<p>Mise à jour du \')';
-        // Modification de la protection : pas de changement de date de l'info récente
-        elseif ( isset($prop['protection']) )
-          $requete = "protection = ${prop['protection']}";
-      break;
+    // Récupération des anciennes propriétés
+    $resultat = $mysqli->query("SELECT matiere, titre, lien, texte, protection FROM recents WHERE id = $id AND type = $type");
+    if ( $resultat->num_rows )  {
+      $anciennesprop = $resultat->fetch_assoc();
+      $resultat->free();
+      // Construction de la requête et exécution
+      $requete = ( $publi || ( isset($prop['protection']) && ( $prop['protection'] == 32 ) ) ) ? ", maj = NOW()" : '';
+      foreach ($prop as $champ=>$val)
+        $requete .= ", $champ = '$val'";
+      $requete = substr($requete,1);
+      requete('recents',"UPDATE recents SET $requete WHERE id = $id AND type = $type",$mysqli);
+    }
+    // Si l'élément n'est pas dans la base, il faut le reconstruire
+    // Ne devrait pas servir, à moins d'une erreur dans la base
+    else  {
+      if ( $type == 1 )
+        $resultat = $mysqli->query("SELECT mat AS matiere, CONCAT('.?',p.cle) AS lien, texte, i.protection,
+                                           CONCAT( IF(LENGTH(i.titre),i.titre,'Information'), IF(p.id>1,CONCAT(' [',IF(mat=0,'',CONCAT(m.nom,'/')),p.nom,']'),'') ) AS titre
+                                    FROM infos AS i LEFT JOIN pages AS p ON page=p.id LEFT JOIN matieres AS m ON mat=m.id WHERE i.id = $id");
+      elseif ( $type == 2 )
+        $resultat = $mysqli->query("SELECT matiere, CONCAT('Colles du ',DATE_FORMAT(debut,'%e/%m'),' en ',nom) AS titre,
+                                           CONCAT('colles?',cle,'&amp;n=',semaine) AS lien, texte, colles_protection AS protection
+                                    FROM colles LEFT JOIN matieres ON matiere=matieres.id LEFT JOIN semaines ON semaine=semaines.id
+                                    WHERE colles.id = $id");
+      elseif ( $type == 3 )
+        $resultat = $mysqli->query("SELECT d.matiere, d.nom AS titre, 'download?id=$id' AS lien, d.protection, 
+                                           CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' )) AS texte
+                                    FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) WHERE d.id = $id");
+      elseif ( $type == 4 )
+        $resultat = $mysqli->query("SELECT matiere, CONCAT(SUBSTRING(debut,9,2),'/',SUBSTRING(debut,6,2),' - ',t.nom,IF(matiere>0, CONCAT(' en ',m.nom),'')) AS titre,
+                                           CONCAT('agenda?mois=',SUBSTRING(debut,3,2),SUBSTRING(debut,6,2)) AS lien, texte, 0 AS protection
+                                    FROM agenda LEFT JOIN matieres AS m ON matiere = m.id LEFT JOIN `agenda-types` AS t ON type = t.id WHERE agenda.id = $id");
+      $prop = array_map($mysqli->real_escape_string,$resultat->fetch_assoc());
+      $resultat->free();
+      requete('recents',"INSERT INTO recents SET id=$id, type=$type, publi = NOW(), matiere = ${prop['matiere']}, titre = '${prop['titre']}', lien = '${prop['lien']}', texte = '${prop['texte']}', protection = ${prop['protection']}",$mysqli);
     }
-    requete('recents',"UPDATE recents SET $requete WHERE id=".($type*1000+$id),$mysqli);
-  }
-  
-  // Pas la peine d'aller plus loin si la table n'a pas été modifiée.
-  if ( !($mysqli->affected_rows) )  {
-    // Cas de la mise à jour de document sans info récente liée : on en crée une
-    if ( ( $type == 3 ) && isset($prop['maj']) )
-      recent($mysqli,3,$id,$matiere,array('titre'=>$prop['maj'], 'lien'=>"download?id=$id", 'texte'=>"<p>Mise à jour du document&nbsp;: <a href=\"download?id=$id\">${prop['maj']}</a></p>", 'matiere'=>$matiere, 'protection'=>$prop['p']),$prop['e']);
-    return;
   }
-
   // Mise dans l'ordre, les plus récents en premier
-  $mysqli->query('ALTER TABLE recents ORDER BY heure DESC');
+  $mysqli->query('ALTER TABLE recents ORDER BY publi DESC');
+  // Sélection des matières concernées pour la régénération des flux
+  $matieres = ( !isset($prop['matiere']) || !isset($anciennesprop['matiere']) ) ? ( $prop['matiere'] ?? $anciennesprop['matiere'] ) : array( $prop['matiere'], $anciennesprop['matiere'] );
+  // Sélection des autorisations concernées pour la régénération des flux
+  // Si $prop['protection'] seule existe, c'est un ajout ou la modification d'une autre propriété
+  // Si $ancienne['protection'] seule existe, c'est une suppression
+  // Dans les deux cas, on modifie les flux correspondant, aucun si 32.
+  if ( !isset($prop['protection']) || !isset($anciennesprop['protection']) )
+    // Si ajout/suppression avec protection=32, rien à faire pour les flux RSS
+    if ( ( $protection = $prop['protection'] ?? $anciennesprop['protection'] ) == 32 )
+      return true;
+  // Si c'est une modification de protection, les deux existent
+  else
+    $protection = ( $prop['protection'] && $anciennesprop['protection'] ) ? $prop['protection']^$anciennesprop['protection'] : 0;
   // Regénération des flux
-  $matieres = array(0);
-  if ( $matiere )
-    $matieres[] = $matiere;
-  // Cas des documents déplacés : deux flux à regénérer
-  if ( isset($prop['matiere']) && ( $matiere != $prop['matiere'] ) )
-    $matieres[] = $prop['matiere'];
-  rss($mysqli,$matieres);
+  rss($mysqli,$matieres,$protection);
+  return true;
 }
 
 // Fonction de mise à jour des flux RSS
-// $matieres doit être soit zéro ou un identifiant de matière
-function rss($mysqli,$matieres)  {
-  $requete = '';
-  foreach ( $matieres as $matiere ) 
-    $requete .= " OR FIND_IN_SET($matiere,matieres)";
+// $matieres doit être soit zéro (toutes matières) ou un identifiant de matière
+// $protection correspond à la protection de la nouveauté/mise à jour
+// Si $protection est nul, il faut remettre à jour tous les flux
+function rss($mysqli,$matieres,$protection)  {
+  if ( !is_array($matieres) )
+    $requete = " OR FIND_IN_SET($matieres,matieres)";
+  else  {
+    $requete = '';
+    foreach ( $matieres as $matiere ) 
+      $requete .= " OR FIND_IN_SET($matiere,matieres)";
+  }
+  if ( $protection )  {
+    // $protection est définie comme expliqué avant la fonction acces, ci-dessous.
+    // 32-$protection donne les autorisations, mais il faut retourner la chaîne
+    // et la décaler d'un cran, avant de récupérer les indices des 1 présents.
+    $autorisations = array_keys(str_split('0'.strrev(decbin(32-$protection))),1);
+    foreach ( $autorisations as $autorisation ) 
+      $requete .= " OR autorisation = $autorisation";
+    $combinaisons = array();
+  }
+  else 
+    $combinaisons = array('0|toutes');
   // Récupération de toutes les combinaisons autorisation-matières possibles
-  $combinaisons = array('0|toutes');
   $resultat = $mysqli->query('SELECT CONCAT(autorisation,\'|\',matieres) FROM utilisateurs WHERE '.substr($requete,4));
   while ( $r = $resultat->fetch_row() )
     $combinaisons[] = $r[0];
@@ -390,13 +411,13 @@
   $resultat->free();
   $titre = $r[0];
   $d = date(DATE_RSS);
-  $site = "https://${GLOBALS['site']}";
+  $site = "https://${GLOBALS['domaine']}${GLOBALS['chemin']}";
   $preambule = <<<FIN
 <?xml version="1.0" encoding="UTF-8"?>
 <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
   <channel>
     <title>$titre</title>
-    <atom:link href="$site/REP/rss.xml" rel="self" type="application/rss+xml" />
+    <atom:link href="${site}REP/rss.xml" rel="self" type="application/rss+xml" />
     <link>$site</link>
     <description>$titre - Flux RSS</description>
     <lastBuildDate>$d</lastBuildDate>
@@ -408,12 +429,10 @@
   // Log
   $mois = date('Y-m');
   $heure = date('d/m/Y à H:i:s');
-  if ( file_exists("documents/rss/log.$mois.php") )
-    $fichierlog = fopen("documents/rss/log.$mois.php",'ab');
+  if ( file_exists("rss/log.$mois.php") )
+    $fichierlog = fopen("rss/log.$mois.php",'ab');
   else  {
-    if ( !is_dir('documents/rss') )
-      mkdir('documents/rss',0777);
-    $fichierlog = fopen("documents/rss/log.$mois.php",'wb');
+    $fichierlog = fopen("rss/log.$mois.php",'wb');
     fwrite($fichierlog,'<?php exit(); ?>');
   }
   fwrite($fichierlog, "\n-- Génération le $heure -- ".json_encode($matieres)."\n");
@@ -422,19 +441,25 @@
   foreach ( $combinaisons as $c )  {
     list($autorisation,$matieres) = explode('|',$c);
     $requete = ( $autorisation ) ? "FIND_IN_SET(matiere,'$matieres') AND (".requete_protection($autorisation).')' : 'protection = 0';
-    $resultat = $mysqli->query("SELECT UNIX_TIMESTAMP(heure) AS heure, titre, lien, texte, protection FROM recents
-                                WHERE $requete AND DATEDIFF(NOW(),heure) < 60");
+    $resultat = $mysqli->query("SELECT type, UNIX_TIMESTAMP(publi) AS publi, UNIX_TIMESTAMP(maj) AS maj, titre, lien, texte FROM recents
+                                WHERE $requete AND ( DATEDIFF(NOW(),publi) < 90 OR DATEDIFF(NOW(),maj) < 90 ) ORDER BY IF(maj>0,maj,publi) DESC");
     $rss = '';
     if ( $resultat->num_rows )  {
       while ( $r = $resultat->fetch_assoc() )  {
-        $d = date(DATE_RSS,$r['heure']);
-        $titre = preg_replace('/^<.*span> /','',$r['titre']);
-        $texte = preg_replace('/href="([^h])/',"href=\"$site/\\1",$r['texte']);
+        $d = date(DATE_RSS,$r['maj'] ?: $r['publi']);
+        // Modification pour les documents
+        if ( $r['type'] == 3 )  {
+          $r['titre'] .= strtok($r['texte'],'|');
+          $r['texte'] = 'Document de '.strtok('|')." dans le répertoire <a href=\"${site}docs?rep=".strtok('|').'">'.strtok('|').'</a>';
+        }
+        if ( $r['maj'] )
+          $r['titre'] .= ' (mise à jour)';
+        $texte = preg_replace('/href="([^h])/',"href=\"$site\\1",$r['texte']);
         $rss .= <<<FIN
     <item>
-      <title><![CDATA[$titre]]></title>
-      <link>$site/${r['lien']}</link>
-      <guid isPermaLink="false">${r['heure']}</guid>
+      <title><![CDATA[${r['titre']}]]></title>
+      <link>$site${r['lien']}</link>
+      <guid isPermaLink="false">${r['publi']}</guid>
       <description><![CDATA[$texte]]></description>
       <pubDate>$d</pubDate>
     </item>
@@ -446,7 +471,7 @@
     }
 
     // Mise à jour du flux RSS
-    $rep = 'documents/rss/'.sha1("?!${GLOBALS['base']}$c");
+    $rep = 'rss/'.substr(sha1("?!${GLOBALS['mdp']}|$c"),0,20);
     if ( !is_dir($rep) )
       mkdir($rep,0777,true);
     $fichier = fopen($rep.'/rss.xml','wb');
@@ -457,6 +482,7 @@
     fwrite($fichierlog, "  $c $rep\n");
   }
   fclose($fichierlog);
+  return true;
 }
 
 // Fonction PHP pour le stockage dans la base MySQL de l'ordre "naturel" (1,2,10,11 et non 1,10,11,2)
@@ -480,11 +506,11 @@
 // $protection est une valeur numérique.
 // * si $protection = 0, accès autorisé sans connexion identifiée.
 // * si 0 < $protection < 33, $protection est la représentation décimale de la
-// valeur binaire PACEI (types d'utilisateurs : professeurs, administration,
-// colleurs, élèves, invités) à laquelle on a ajouté 1.
+// valeur binaire PLCEI (types d'utilisateurs : professeurs, lycée, colleurs,
+// élèves, invités) à laquelle on a ajouté 1.
 // Chaque 0 correspond aux accès autorisés, chaque 1 correspond aux protections
 // (accès interdit pour ce type de compte).
-// Exemple : 10 -> PACEI=9=01001 -> autorisé pour P,C,E et interdit pour A et I.
+// Exemple : 10 -> PLCEI=9=01001 -> autorisé pour P,C,E et interdit pour L et I.
 // Le code 32 (interdit pour tous) correspond aux docs/reps/... non visibles.
 // * si $protection = 32, page non affichée dans le menu, non visible sauf pour
 // les professeurs associés à la matière
@@ -492,7 +518,7 @@
 // $titre est le titre de la page affichée si accès refusé ou connexion demandée
 // $actuel est le lien du menu si accès refusé ou connexion demandée
 function acces($protection,$matiere,$titre,$actuel,$mysqli)  {
-  $autorisation = $_SESSION['autorisation'];
+  $autorisation = $_SESSION['autorisation'] ?? 0;
   // Mode édition
   if ( ( $autorisation == 5 ) && in_array($matiere,explode(',',$_SESSION['matieres'])) )
     return !isset($_REQUEST['mode_lecture']);
@@ -540,7 +566,7 @@
     
     // Requête partielles de récupération
     // Non connecté : on voit tout ce qui est non vide et non désactivé
-    // Invité/Élèves/Colleurs/Administration : on voit ce qui est non vide et
+    // Invité/Élèves/Colleurs/Lycée : on voit ce qui est non vide et
     // autorisé (matière associée et protection correcte)
     // Prof : on voit tout ce qui est non vide et autorisé pour les matières non
     // associées, toutes les pages et reps pour les matières associées, tout ce
@@ -569,41 +595,56 @@
         $requete_rss = "FIND_IN_SET(matiere,'${_SESSION['matieres']}') AND ( protection = 0 OR ( (protection-1)>>($autorisation-1) & 1 ) = 0 )";
     }
     
-    // Récupération et affichage des pages
-    $menu = "<a class=\"icon-menu\" title=\"Afficher le menu\"></a>\n<div id=\"colonne\">\n  <nav>\n";
-    $resultat = $mysqli->query("SELECT cle, nom FROM pages WHERE mat = 0 AND (id = 1 OR $requete_pages) ORDER BY ordre");
-    $r = $resultat->fetch_assoc();
     // Icônes principales (accueil, agenda, impression, rss)
-    $menu .= <<<FIN
-    <a class="icon-accueil" href=".?${r['cle']}" title="${r['nom']}"></a>
+    $recents = $_SESSION['recents'] ?? '';
+    $icones = <<<FIN
+  <div id="iconesmenu">
+    <a class="icon-menu" title="Afficher le menu"></a>
+    <a class="icon-accueil" href="." title="Revenir à la page d'accueil"></a>
+    <a class="icon-recent" href="recent" title="Voir les $recents nouveaux contenus">$recents</a>
     <a class="icon-agenda" href="agenda" title="Agenda"></a>
     <a class="icon-imprime" title="Imprimer cette page" onclick="window.print();return false;"></a>
-    <a class="icon-rss" href="rss" title="Voir les flux RSS disponibles"></a>
 
 FIN;
-    // Préférences (tous types de comptes sauf invité)
-    if ( $autorisation > 1 )
-      $menu .= "    <a class=\"icon-prefs\" href=\"prefs\" title=\"Gérer ses préférences\"></a>\n";
-    // Envoi de courriel
-    if ( ( $autorisation > 1 ) && $_SESSION['mailenvoi'] )
-      $menu .= "    <a class=\"icon-mail\" href=\"mail\" title=\"Envoyer un courriel\"></a>\n";
+    // Préférences et mails (tous types de comptes sauf invité)
+    if ( $autorisation > 1 )  {
+      $icones .= "    <a class=\"icon-prefs\" href=\"prefs\" title=\"Gérer ses préférences\"></a>\n";
+      // Autorisation d'envoi de courriel
+      $resultat2 = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+      if ( $resultat2->fetch_row()[0] >> 4*($autorisation-2) & 15 )
+        $icones .= "    <a class=\"icon-mail\" href=\"mail\" title=\"Envoyer un courriel\"></a>\n";
+      $resultat2->free();
+      if ( $_SESSION['compteglobal'] )
+        $icones .= "    <a class=\"icon-echange\" title=\"Changer de Cahier\"></a>\n";
+    }
     // Connexion/Déconnexion
-    $menu .= $autorisation ? "    <a class=\"icon-deconnexion\" title=\"Se déconnecter\"></a>\n    <hr>\n" : "    <a class=\"icon-connexion\" title=\"Se connecter\"></a>\n    <hr>\n";
-    // Relève des colles, compte administratif uniquement
-    if ( $autorisation == 4 )
-      $menu .= "    <a href=\"relevenotes\">Relève des notes</a>\n";
-    // Autres pages
-    while ( $r = $resultat->fetch_assoc() )
-      $menu .= "    <a href=\".?${r['cle']}\">${r['nom']}</a>\n";
+    $icones .= ( ( $autorisation ) ? '    <a class="icon-deconnexion" title="Se déconnecter"></a>' : '    <a class="icon-connexion" title="Se connecter"></a>' )."\n  </div>";
+    
+    ////////////////////////////
+    // Menu : pages générales //
+    ////////////////////////////
+    
+    // Pages d'information générales
+    $resultat = $mysqli->query("SELECT cle, nom FROM pages WHERE mat = 0 AND (id = 1 OR $requete_pages) ORDER BY ordre");
+    $menu = "  <hr>\n";
+    if ( $resultat->num_rows > 1 )  {
+      while ( $r = $resultat->fetch_assoc() )
+        $menu .= "  <a href=\".?${r['cle']}\">${r['nom']}</a>\n";
+    }
     $resultat->free();
     // Page de téléchargement
-    $menu .= "    <a href=\"docs\">Documents à télécharger</a>\n";
+    $menu .= "  <a href=\"docs\"><span class=\"icon-rep\"></span>&nbsp;Documents à télécharger</a>\n";
     $resultat = $mysqli->query("SELECT id, nom FROM reps WHERE matiere = 0 AND menu = 1 AND ( $requete_reps )");
     if ( $resultat->num_rows )  {
       while ( $r = $resultat->fetch_assoc() )
-        $menu .= "      <a class=\"menurep\" href=\"docs?rep=${r['id']}\">${r['nom']}</a>\n";
+        $menu .= "    <a class=\"menurep\" href=\"docs?rep=${r['id']}\">${r['nom']}</a>\n";
       $resultat->free();
     }
+
+    /////////////////////
+    // Menu : matières //
+    /////////////////////
+    
     // Récupération et affichage des matières
     $resultat = $mysqli->query('SELECT * FROM (
                                   SELECT m.id, m.cle, m.nom,
@@ -621,75 +662,75 @@
     if ( $resultat->num_rows )  {
       while ( $r = $resultat->fetch_assoc() )  {
         $edition = ( $autorisation == 5 ) && ( in_array($r['id'],explode(',',$_SESSION['matieres'])) );
-        $menu .= "    <h3>${r['nom']}</h3>\n";
+        $menu .= "  <h3>${r['nom']}</h3>\n";
         if ( !is_null($r['pcle']) )  {
           $pcle = explode('//',$r['pcle']);
           $pnom = explode('//',$r['pnom']);
           $nom = $pnom[0];
           foreach ( $pcle as $cle )  {
-            $menu .= "    <a href=\".?$cle\">$nom</a>\n";
+            $menu .= "  <a href=\".?$cle\">$nom</a>\n";
             $nom = next($pnom);
           }
         }
         if ( $r['colles'] )
-          $menu .= "    <a href=\"colles?${r['cle']}\">Programme de colles</a>\n";
+          $menu .= "  <a href=\"colles?${r['cle']}\"><span class=\"icon-colles\"></span>&nbsp;Programme de colles</a>\n";
         if ( $r['docs'] )  {
-          $menu .= "    <a href=\"docs?${r['cle']}\">Documents à télécharger</a>\n";
+          $menu .= "  <a href=\"docs?${r['cle']}\"><span class=\"icon-rep\"></span>&nbsp;Documents à télécharger</a>\n";
           $resultat_doc = $mysqli->query("SELECT id, nom FROM reps WHERE matiere = ${r['id']} AND menu = 1 AND ( $requete_reps )");
           if ( $resultat_doc->num_rows )  {
             while ( $d = $resultat_doc->fetch_assoc() )
-              $menu .= "    <a class=\"menurep\" href=\"docs?rep=${d['id']}\">${d['nom']}</a>\n";        
+              $menu .= "  <a class=\"menurep\" href=\"docs?rep=${d['id']}\">${d['nom']}</a>\n";        
             $resultat_doc->free();
           }
         }
         if ( $r['cdt'] )  {
-          $menu .= "    <a href=\"cdt?${r['cle']}\">Cahier de texte</a>\n";
+          $menu .= "  <a href=\"cdt?${r['cle']}\"><span class=\"icon-cdt\"></span>&nbsp;Cahier de texte</a>\n";
           if ( $edition && ( substr($actuel,0,3) == 'cdt' ) && ( substr($actuel,-strlen($r['cle'])-1) == "?${r['cle']}" ) )
-            $menu .= "      <a class=\"menurep\" href=\"cdt-seances?${r['cle']}\">Types de séances</a>\n      <a class=\"menurep\" href=\"cdt-raccourcis?${r['cle']}\">Raccourcis de séances</a>\n";
+            $menu .= "    <a class=\"menurep\" href=\"cdt-seances?${r['cle']}\">Types de séances</a>\n    <a class=\"menurep\" href=\"cdt-raccourcis?${r['cle']}\">Raccourcis de séances</a>\n";
         }
         if ( $r['notes'] )
-          $menu .= "    <a href=\"notes?${r['cle']}\">Notes</a>\n";
+          $menu .= "  <a href=\"notes?${r['cle']}\"><span class=\"icon-notes\"></span>&nbsp;Notes</a>\n";
       }
       $resultat->free();
     }
+
+    ////////////////////
+    // Administration //
+    ////////////////////
+
+    // Relève des colles, compte lycée uniquement
+    if ( $autorisation == 4 )
+      $menu .= "    <a href=\"relevenotes\">Relève des notes</a>\n";
     // Liens d'édition, professeurs seulement
     if ( $autorisation == 5 )
       $menu .= <<<FIN
-    <h3>Gestion du site</h3>
-    <a href="pages">Les pages</a>
-    <a href="matieres">Les matières</a>
-    <a href="utilisateurs">Les utilisateurs</a>
-    <a href="utilisateurs-matieres">Les associations utilisateurs-matières</a>
-    <a href="groupes">Les groupes</a>
-    <a href="planning">Le planning annuel</a>
+  <h3>Gestion du site</h3>
+  <a href="pages">Les pages</a>
+  <a href="matieres">Les matières</a>
+  <a href="utilisateurs">Les utilisateurs</a>
+  <a href="utilisateurs-matieres">Les associations utilisateurs-matières</a>
+  <a href="utilisateurs-mails">Les courriels</a>
+  <a href="groupes">Les groupes</a>
+  <a href="planning">Le planning annuel</a>
 
 FIN;
     $menu = str_replace("a href=\"$actuel\"","a id=\"actuel\" href=\"$actuel\"",$menu);
-    $menu .= '  </nav>';
-
-    // Affichage des informations récentes
-    $recent = '';
-    $resultat = $mysqli->query("SELECT titre, lien FROM recents WHERE DATEDIFF(NOW(),heure) < 15 AND $requete_rss LIMIT 20");
-    if ( $resultat->num_rows )  {
-      $menu = "<a class=\"icon-recent\" title=\"Afficher les informations récentes\"></a>\n$menu";
-      while ( $r = $resultat->fetch_assoc() )
-        $recent .= "\n    <a href=\"${r['lien']}\" title=\"".substr($r['titre'],strpos($r['titre'],'/span>')+7)."\">${r['titre']}</a>";
-      $resultat->free();
-      $recent = <<<FIN
-  <div id="recent">
-    <h3>Infos récentes</h3>$recent
-  </div>
+    // Menu final
+    $menu = <<<FIN
+<nav>
+$icones
+$menu
+</nav>
 
 FIN;
-    }
   }
   else
-    $menu = $recent = '';
-  if ( strlen($menu.$recent) )
-    $recent .= '</div>';
-    
-  // RSS
-  $rss = ( $autorisation ) ? sha1("?!${GLOBALS['base']}$autorisation|${_SESSION['matieres']}") : sha1("?!${GLOBALS['base']}0|toutes");
+    $menu = '';
+  
+  //////////
+  // HTML //
+  //////////
+  
   // Message si non vide
   if ( strlen($message) )
     $message = "  <div class=\"warning\">$message</div>\n";
@@ -701,6 +742,8 @@
       $message = '  <div class="warning">Il y a actuellement '.(( $n > 1 ) ? "$n comptes" : "1 compte").' en attente de validation de votre part. C\'est assez urgent... Il faut aller sur la page de gestion des <a href="utilisateurs">utilisateurs</a> pour les valider.</div>';
     }
   }
+  // Flux RSS
+  $rss = substr(sha1( ( $autorisation ) ? "?!${GLOBALS['mdp']}|$autorisation|${_SESSION['matieres']}" : "?!${GLOBALS['mdp']}|0|toutes" ),0,20);
   // Token CSRF
   $token = ( isset($_SESSION['csrf-token']) ) ? " data-csrf-token=\"${_SESSION['csrf-token']}\"" : '';
   // Matière
@@ -717,17 +760,16 @@
   <title>$head</title>
   <meta charset="utf-8">
   <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1.0">
-  <link rel="stylesheet" href="css/style.min.css?v=810">
-  <link rel="stylesheet" href="css/icones.min.css?v=810">$css
+  <link rel="stylesheet" href="css/style.min.css?v=900">
+  <link rel="stylesheet" href="css/icones.min.css?v=900">$css
   <script type="text/javascript" src="js/jquery.min.js"></script>
-  <link rel="alternate" type="application/rss+xml" title="Flux RSS" href="documents/rss/$rss/rss.xml">
+  <link rel="alternate" type="application/rss+xml" title="Flux RSS" href="rss/$rss/rss.xml">
 </head>
 <body$token$matiere>
 
 <header><h1>$titre</h1></header>
 
 $menu
-$recent
 
 <section>
 $message
@@ -741,7 +783,7 @@
 <script type="text/javascript" src="/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
 <script type="text/x-mathjax-config">MathJax.Hub.Config({tex2jax:{inlineMath:[["$","$"],["\\\\(","\\\\)"]]}});</script>' : '';
   // Édition possible si $edition est true
-  $js = ( $edition ) ? '<script type="text/javascript" src="js/edition.min.js?v=810"></script>' : '<script type="text/javascript" src="js/fonctions.min.js?v=810"></script>';
+  $js = ( $edition ) ? '<script type="text/javascript" src="js/edition.min.js?v=900"></script>' : '<script type="text/javascript" src="js/fonctions.min.js?v=900"></script>';
   // Affichage de message si $_SESSION['message']
   if ( isset($_SESSION['message']) )  {
     $m = json_decode($_SESSION['message'],true);
Binary files cahier-de-prepa8.1.1/fonts/icomoon.eot and cahier-de-prepa9.0.0/fonts/icomoon.eot differ
diff -urN cahier-de-prepa8.1.1/fonts/icomoon.svg cahier-de-prepa9.0.0/fonts/icomoon.svg
--- cahier-de-prepa8.1.1/fonts/icomoon.svg	2018-10-09 01:19:20.059315070 +0200
+++ cahier-de-prepa9.0.0/fonts/icomoon.svg	1970-01-01 01:00:00.000000000 +0100
@@ -1,99 +0,0 @@
-<?xml version="1.0" standalone="no"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
-<svg xmlns="http://www.w3.org/2000/svg">
-<metadata>Generated by IcoMoon</metadata>
-<defs>
-<font id="icomoon" horiz-adv-x="1024">
-<font-face units-per-em="1024" ascent="960" descent="-64" />
-<missing-glyph horiz-adv-x="1024" />
-<glyph unicode="&#x20;" horiz-adv-x="512" d="" />
-<glyph unicode="&#xe600;" glyph-name="montre" d="M512 768c-223.318 0-416.882-130.042-512-320 95.118-189.958 288.682-320 512-320 223.312 0 416.876 130.042 512 320-95.116 189.958-288.688 320-512 320zM764.45 598.296c60.162-38.374 111.142-89.774 149.434-150.296-38.292-60.522-89.274-111.922-149.436-150.296-75.594-48.218-162.89-73.704-252.448-73.704-89.56 0-176.858 25.486-252.452 73.704-60.158 38.372-111.138 89.772-149.432 150.296 38.292 60.524 89.274 111.924 149.434 150.296 3.918 2.5 7.876 4.922 11.86 7.3-9.96-27.328-15.41-56.822-15.41-87.596 0-141.382 114.616-256 256-256 141.382 0 256 114.618 256 256 0 30.774-5.452 60.268-15.408 87.598 3.978-2.378 7.938-4.802 11.858-7.302v0zM512 544c0-53.020-42.98-96-96-96s-96 42.98-96 96 42.98 96 96 96 96-42.982 96-96z" />
-<glyph unicode="&#xe601;" glyph-name="cache" d="M945.942 945.942c-18.746 18.744-49.136 18.744-67.882 0l-202.164-202.164c-51.938 15.754-106.948 24.222-163.896 24.222-223.318 0-416.882-130.042-512-320 41.122-82.124 100.648-153.040 173.022-207.096l-158.962-158.962c-18.746-18.746-18.746-49.136 0-67.882 9.372-9.374 21.656-14.060 33.94-14.060s24.568 4.686 33.942 14.058l864 864c18.744 18.746 18.744 49.138 0 67.884zM416 640c42.24 0 78.082-27.294 90.92-65.196l-121.724-121.724c-37.902 12.838-65.196 48.68-65.196 90.92 0 53.020 42.98 96 96 96zM110.116 448c38.292 60.524 89.274 111.924 149.434 150.296 3.918 2.5 7.876 4.922 11.862 7.3-9.962-27.328-15.412-56.822-15.412-87.596 0-54.89 17.286-105.738 46.7-147.418l-60.924-60.924c-52.446 36.842-97.202 83.882-131.66 138.342zM768 518c0 27.166-4.256 53.334-12.102 77.898l-321.808-321.808c24.568-7.842 50.742-12.090 77.91-12.090 141.382 0 256 114.618 256 256zM830.026 670.026l-69.362-69.362c1.264-0.786 2.53-1.568 3.786-2.368 60.162-38.374 111.142-89.774 149.434-150.296-38.292-60.522-89.274-111.922-149.436-150.296-75.594-48.218-162.89-73.704-252.448-73.704-38.664 0-76.902 4.76-113.962 14.040l-76.894-76.894c59.718-21.462 123.95-33.146 190.856-33.146 223.31 0 416.876 130.042 512 320-45.022 89.916-112.118 166.396-193.974 222.026z" />
-<glyph unicode="&#xe602;" glyph-name="aide" d="M448 256h128v-128h-128zM704 704c35.346 0 64-28.654 64-64v-192l-192-128h-128v64l192 128v64h-320v128h384zM512 864c-111.118 0-215.584-43.272-294.156-121.844s-121.844-183.038-121.844-294.156c0-111.118 43.272-215.584 121.844-294.156s183.038-121.844 294.156-121.844c111.118 0 215.584 43.272 294.156 121.844s121.844 183.038 121.844 294.156c0 111.118-43.272 215.584-121.844 294.156s-183.038 121.844-294.156 121.844zM512 960v0c282.77 0 512-229.23 512-512s-229.23-512-512-512c-282.77 0-512 229.23-512 512s229.23 512 512 512z" />
-<glyph unicode="&#xe603;" glyph-name="ajoute" d="M992 576h-352v352c0 17.672-14.328 32-32 32h-192c-17.672 0-32-14.328-32-32v-352h-352c-17.672 0-32-14.328-32-32v-192c0-17.672 14.328-32 32-32h352v-352c0-17.672 14.328-32 32-32h192c17.672 0 32 14.328 32 32v352h352c17.672 0 32 14.328 32 32v192c0 17.672-14.328 32-32 32z" />
-<glyph unicode="&#xe604;" glyph-name="supprime" d="M0 544v-192c0-17.672 14.328-32 32-32h960c17.672 0 32 14.328 32 32v192c0 17.672-14.328 32-32 32h-960c-17.672 0-32-14.328-32-32z" />
-<glyph unicode="&#xe605;" glyph-name="annule" d="M761.862-64c113.726 206.032 132.888 520.306-313.862 509.824v-253.824l-384 384 384 384v-248.372c534.962 13.942 594.57-472.214 313.862-775.628z" />
-<glyph unicode="&#xe606;" glyph-name="ok" d="M864 832l-480-480-224 224-160-160 384-384 640 640z" />
-<glyph unicode="&#xe607;" glyph-name="prefs" d="M896 512h16c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v192h-128v-192h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-576h128v576zM768 704h128v-128h-128v128zM592 128c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v576h-128v-576h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-192h128v192h16zM448 320h128v-128h-128v128zM272 512c26.4 0 48 21.6 48 48v160c0 26.4-21.6 48-48 48h-16v192h-128v-192h-16c-26.4 0-48-21.6-48-48v-160c0-26.4 21.6-48 48-48h16v-576h128v576h16zM128 704h128v-128h-128v128z" />
-<glyph unicode="&#xe608;" glyph-name="monte" d="M762.453 512v-436.907h72.818v436.907h182.045l-218.453 218.453-218.453-218.453zM34.275 876.089h109.227v-72.818h-109.227v72.818zM179.911 876.089h109.227v-72.818h-109.227v72.818zM325.547 876.089h72.818v-109.227h-72.818v109.227zM34.275 621.227h72.818v-109.227h-72.818v109.227zM143.502 584.818h109.227v-72.818h-109.227v72.818zM289.138 584.818h109.227v-72.818h-109.227v72.818zM34.275 766.862h72.818v-109.227h-72.818v109.227zM325.547 730.453h72.818v-109.227h-72.818v109.227zM325.547 293.547v-218.453h-218.453v218.453h218.453zM398.365 366.365h-364.089v-364.089h364.089v364.089z" />
-<glyph unicode="&#xe609;" glyph-name="descend" d="M835.271 293.547v436.907h-72.818v-436.907h-182.045l218.453-218.453 218.453 218.453zM325.547 803.271v-218.453h-218.453v218.453h218.453zM398.365 876.089h-364.089v-364.089h364.089v364.089zM34.275 366.365h109.227v-72.818h-109.227v72.818zM179.911 366.365h109.227v-72.818h-109.227v72.818zM325.547 366.365h72.818v-109.227h-72.818v109.227zM34.275 111.502h72.818v-109.227h-72.818v109.227zM143.502 75.093h109.227v-72.818h-109.227v72.818zM289.138 75.093h109.227v-72.818h-109.227v72.818zM34.275 257.138h72.818v-109.227h-72.818v109.227zM325.547 220.729h72.818v-109.227h-72.818v109.227z" />
-<glyph unicode="&#xe60a;" glyph-name="ferme" d="M512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416zM672 704l-160-160-160 160-96-96 160-160-160-160 96-96 160 160 160-160 96 96-160 160 160 160z" />
-<glyph unicode="&#xe60b;" glyph-name="epingle" d="M544 960l-96-96 96-96-224-256h-224l176-176-272-360.616v-39.384h39.384l360.616 272 176-176v224l256 224 96-96 96 96-480 480zM448 416l-64 64 224 224 64-64-224-224z" />
-<glyph unicode="&#xe60c;" glyph-name="par1" d="M384 960h512v-128h-128v-896h-128v896h-128v-896h-128v512c-141.384 0-256 114.616-256 256s114.616 256 256 256z" />
-<glyph unicode="&#xe60d;" glyph-name="par2" d="M356 960h512v-128h-128v-896h-128v896h-128v-896h-128v512c-141.384 0-256 114.616-256 256s114.616 256 256 256zM807.99 483.564h66.348v-180.252l-6.52-96.742-53.021-0.096-6.807 97.509zM807.99 144.537h66.252v-69.8h-66.252v69.8z" />
-<glyph unicode="&#xe60e;" glyph-name="par3" d="M308 960h512v-128h-128v-896h-128v896h-128v-896h-128v512c-141.384 0-256 114.616-256 256s114.616 256 256 256zM759.99 483.564h66.348v-180.252l-6.52-96.742-53.021-0.096-6.807 97.509zM759.99 144.537h66.252v-69.8h-66.252v69.8zM892.336 483.573h66.348v-180.252l-6.52-96.742-53.021-0.096-6.807 97.509zM892.336 144.546h66.252v-69.8h-66.252v69.8z" />
-<glyph unicode="&#xe60f;" glyph-name="gras" d="M734.868 479.116c42.665 50.678 68.403 116.063 68.403 187.338 0 160.609-130.665 291.271-291.271 291.271h-364.089v-1019.449h436.907c160.607 0 291.271 130.665 291.271 291.271 0 105.763-56.659 198.538-141.221 249.569zM366.365 812.089h115.485c63.679 0 115.485-65.331 115.485-145.635s-51.805-145.635-115.485-145.635h-115.485v291.271zM547.271 83.911h-180.907v291.271h180.907c66.503 0 120.605-65.331 120.605-145.635s-54.101-145.635-120.605-145.635z" />
-<glyph unicode="&#xe610;" glyph-name="italique" d="M948.907 957.725v-72.818h-145.635l-364.089-873.813h145.635v-72.818h-509.725v72.818h145.635l364.089 873.813h-145.635v72.818z" />
-<glyph unicode="&#xe611;" glyph-name="souligne" d="M730.453 957.725h145.635v-473.315c0-180.973-163.007-327.68-364.089-327.68-201.079 0-364.089 146.707-364.089 327.68v473.315h145.635v-473.315c0-45.7 20.751-89.548 58.43-123.456 41.98-37.779 98.812-58.589 160.023-58.589s118.045 20.81 160.023 58.589c37.679 33.908 58.43 77.756 58.43 123.456v473.315zM147.911 83.911h728.178v-145.635h-728.178z" />
-<glyph unicode="&#xe612;" glyph-name="omega" d="M704 64h256l64 128v-256h-384v214.214c131.112 56.484 224 197.162 224 361.786 0 214.432-157.598 382.266-352 382.266-194.406 0-352-167.832-352-382.266 0-164.624 92.886-305.302 224-361.786v-214.214h-384v256l64-128h256v32.59c-187.63 66.46-320 227.402-320 415.41 0 247.424 229.23 448 512 448s512-200.576 512-448c0-188.008-132.37-348.95-320-415.41v-32.59z" />
-<glyph unicode="&#xe613;" glyph-name="sigma" d="M941.606 225.292l44.394 94.708h38l-64-384h-960v74.242l331.546 391.212-331.546 331.546v227h980l44-256h-34.376l-18.72 38.88c-35.318 73.364-61.904 89.12-138.904 89.12h-662l353.056-353.056-297.42-350.944h542.364c116.008 0 146.648 41.578 173.606 97.292z" />
-<glyph unicode="&#xe614;" glyph-name="exp" d="M768 754v-50h128v-64h-192v146l128 60v50h-128v64h192v-146zM676 704h-136l-188-188-188 188h-136l256-256-256-256h136l188 188 188-188h136l-256 256z" />
-<glyph unicode="&#xe615;" glyph-name="ind" d="M768 50v-50h128v-64h-192v146l128 60v50h-128v64h192v-146zM676 704h-136l-188-188-188 188h-136l256-256-256-256h136l188 188 188-188h136l-256 256z" />
-<glyph unicode="&#xe616;" glyph-name="ol" d="M384 128h640v-128h-640zM384 512h640v-128h-640zM384 896h640v-128h-640zM192 960v-256h-64v192h-64v64zM128 434v-50h128v-64h-192v146l128 60v50h-128v64h192v-146zM256 256v-320h-192v64h128v64h-128v64h128v64h-128v64z" />
-<glyph unicode="&#xe617;" glyph-name="ul" d="M384 896h640v-128h-640v128zM384 512h640v-128h-640v128zM384 128h640v-128h-640v128zM0 832c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128zM0 448c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128zM0 64c0 70.692 57.308 128 128 128s128-57.308 128-128c0-70.692-57.308-128-128-128s-128 57.308-128 128z" />
-<glyph unicode="&#xe618;" glyph-name="lien1" d="M665.832 632.952l-64.952 64.922-324.81-324.742c-53.814-53.792-53.814-141.048 0-194.844 53.804-53.792 141.060-53.792 194.874 0l389.772 389.708c89.714 89.662 89.714 235.062 0 324.726-89.666 89.704-235.112 89.704-324.782 0l-409.23-409.178c-0.29-0.304-0.612-0.576-0.876-0.846-125.102-125.096-125.102-327.856 0-452.906 125.054-125.056 327.868-125.056 452.988 0 0.274 0.274 0.516 0.568 0.82 0.876l0.032-0.034 279.332 279.292-64.986 64.92-279.33-279.262c-0.296-0.268-0.564-0.57-0.846-0.844-89.074-89.058-233.98-89.058-323.076 0-89.062 89.042-89.062 233.922 0 322.978 0.304 0.304 0.604 0.582 0.888 0.846l-0.046 0.060 409.28 409.166c53.712 53.738 141.144 53.738 194.886 0 53.712-53.734 53.712-141.148 0-194.84l-389.772-389.7c-17.936-17.922-47.054-17.922-64.972 0-17.894 17.886-17.894 47.032 0 64.92l324.806 324.782z" />
-<glyph unicode="&#xe619;" glyph-name="lien2" d="M440.236 324.234c-13.31 0-26.616 5.076-36.77 15.23-95.134 95.136-95.134 249.934 0 345.070l192 192c46.088 46.086 107.36 71.466 172.534 71.466s126.448-25.38 172.536-71.464c95.132-95.136 95.132-249.934 0-345.070l-87.766-87.766c-20.308-20.308-53.23-20.308-73.54 0-20.306 20.306-20.306 53.232 0 73.54l87.766 87.766c54.584 54.586 54.584 143.404 0 197.99-26.442 26.442-61.6 41.004-98.996 41.004s-72.552-14.562-98.996-41.006l-192-191.998c-54.586-54.586-54.586-143.406 0-197.992 20.308-20.306 20.306-53.232 0-73.54-10.15-10.152-23.462-15.23-36.768-15.23zM256-52c-65.176 0-126.45 25.38-172.534 71.464-95.134 95.136-95.134 249.934 0 345.070l87.764 87.764c20.308 20.306 53.234 20.306 73.54 0 20.308-20.306 20.308-53.232 0-73.54l-87.764-87.764c-54.586-54.586-54.586-143.406 0-197.992 26.44-26.44 61.598-41.002 98.994-41.002s72.552 14.562 98.998 41.006l192 191.998c54.584 54.586 54.584 143.406 0 197.992-20.308 20.308-20.306 53.232 0 73.54 20.306 20.306 53.232 20.306 73.54-0.002 95.132-95.134 95.132-249.932 0.002-345.068l-192.002-192c-46.090-46.088-107.364-71.466-172.538-71.466z" />
-<glyph unicode="&#xe61a;" glyph-name="retour" d="M448 184.372v-248.372l-384 384 384 384v-253.824c446.75-10.48 427.588 303.792 313.862 509.824 280.71-303.414 221.1-789.57-313.862-775.628z" />
-<glyph unicode="&#xe61b;" glyph-name="source" horiz-adv-x="1216" d="M608 920.412c-212.869 0-397.376-116.767-488.044-287.334 90.668-170.567 275.174-287.334 488.044-287.334 212.863 0 397.371 116.767 488.044 287.334-90.666 170.567-275.181 287.334-488.044 287.334zM848.638 768.032c57.347-34.457 105.941-80.61 142.442-134.954-36.5-54.343-85.097-100.497-142.444-134.954-72.057-43.296-155.268-66.18-240.636-66.18-85.37 0-168.582 22.884-240.64 66.18-57.343 34.455-105.938 80.608-142.441 134.954 36.5 54.346 85.097 100.499 142.442 134.954 3.734 2.245 7.507 4.419 11.306 6.555-9.494-24.539-14.689-51.022-14.689-78.654 0-126.949 109.253-229.868 244.021-229.868s244.021 102.917 244.021 229.868c0 27.633-5.197 54.116-14.687 78.656 3.792-2.135 7.567-4.311 11.303-6.557v0zM608 719.278c0-47.607-40.969-86.201-91.508-86.201s-91.508 38.593-91.508 86.201c0 47.607 40.969 86.201 91.508 86.201s91.508-38.594 91.508-86.201zM257.918 61.409l0.41 295.358 35.59-0.41-0.818-118.225c0 0 8.591 31.090 47.454 40.499s62.998-9.409 62.998-9.409c0 0 17.141-11.226 21.273-34.363 5.108-28.607 2.454-173.86 2.454-173.86h-36.409l0.818 147.679c0 0 3.365 60.563-62.18 40.909-31.287-9.382-36.817-56.863-36.817-56.863l0.41-131.725zM458.778 276.587l0.41-26.591 24.545-0.41-0.511-151.566c0 0 0.236-25.456 16.364-33.238 26.797-12.929 61.056-2.352 61.056-2.352v27.613c0 0-16.089-7.75-30.682-2.454-12.682 4.603-11.761 24.545-11.761 24.545l0.307 137.861 38.863 0.41-0.41 26.181h-38.453l-0.41 47.862h-23.727l-9.409-47.862zM590.644 276.465l0.289-215.708 34.133 0.017 0.578 133.538c0 0-2.217 48.206 38.762 57.275 51.994 11.506 49.175-40.786 49.175-40.786l-0.578-149.84 35.002 0.289v132.773c0 0-1.691 58.148 52.646 58.721 35.268 0.371 33.844-41.365 33.844-41.365l0.578-150.418h34.711l0.578 156.493c0 0 0.027 61.476-50.043 62.77-63.134 1.632-76.077-41.365-76.077-41.365s-3.858 36.678-45.994 40.497c-59.625 5.404-73.763-40.786-73.763-40.786l-0.868 37.893zM927.201 60.847l30.666 0.154v295.266h-34.831l0.051-295.42zM1004.8 267.86l167.164-72.86-167.164-73.003v-30.481l193.7 82.983v40.966l-193.799 83.1zM210.667 267.594l-167.164-72.86 167.164-73.003v-30.481l-193.7 82.983v40.966l193.799 83.1z" />
-<glyph unicode="&#xe61c;" glyph-name="nosource" horiz-adv-x="1216" d="M954.010 804.177c-14.806 7.659-132.612 114.099-346.010 116.236-212.859 2.13-397.376-116.767-488.044-287.334 63.468-124.701 216.508-262.801 426.71-284.134zM608 431.943c-85.37 0-168.582 22.884-240.64 66.18-57.343 34.455-105.938 80.608-142.441 134.954 36.5 54.346 85.097 100.499 142.442 134.954 3.734 2.245 7.507 4.419 11.306 6.555-9.494-24.539-14.689-51.022-14.689-78.654 0-126.949 109.253-229.868 244.021-229.868s244.021 102.917 244.021 229.868c0 27.633-5.197 54.116-14.687 78.656 3.792-2.135 7.567-4.311 11.303-6.557 57.347-34.457-3.925 23.923 32.575-30.42zM608 719.278c0-47.607-40.969-86.201-91.508-86.201s-91.508 38.593-91.508 86.201c0 47.607 40.969 86.201 91.508 86.201s91.508-38.594 91.508-86.201zM257.918 61.409l0.41 295.358 35.59-0.41-0.818-118.225c0 0 8.591 31.090 47.454 40.499s62.998-9.409 62.998-9.409c0 0 17.141-11.226 21.273-34.363 5.108-28.607 2.454-30.927 2.454-30.927l-36.409-28.8 0.818 33.546c0 0 3.365 60.563-62.18 40.909-31.287-9.382-36.817-56.863-36.817-56.863l0.41-131.725zM483.265 167.799l-0.045-69.778c0 0 0.236-25.456 16.364-33.238 26.797-12.929 61.056-2.352 61.056-2.352v27.613c0 0-16.089-7.75-30.682-2.454-12.682 4.603-11.761 24.545-11.761 24.545l0.203 91.198-13.657-13.467zM590.644 276.465l0.289-215.708 34.133 0.017 0.578 133.538c0 0-2.217 48.206 38.762 57.275 51.994 11.506 49.175-40.786 49.175-40.786l-0.578-149.84 35.002 0.289v132.773c0 0-1.691 58.148 52.646 58.721 35.268 0.371 33.844-41.365 33.844-41.365l0.578-150.418h34.711l0.578 156.493c0 0 0.027 61.476-50.043 62.77-63.134 1.632-76.077-41.365-76.077-41.365s-3.858 36.678-45.994 40.497c-59.625 5.404-73.763-40.786-73.763-40.786l-0.868 37.893zM927.201 60.847l30.666 0.154v295.266h-34.831l0.051-295.42zM1004.8 267.86l167.164-72.86-167.164-73.003v-30.481l193.7 82.983v40.966l-193.799 83.1zM210.667 267.594l-167.164-72.86 167.164-73.003v-30.481l-193.7 82.983v40.966l193.799 83.1zM116.121 29.914c0 0-41.879-39.28-6.4-78.933 36.267-40.533 81.067 8.533 81.067 8.533l906.667 906.667c0 0 44.8 36.267 9.597 74.667-39.275 42.842-75.73 4.267-75.73 4.267zM390.869 75.65l0.023-14.496 36.015-0.117 0.873 51.454zM664.127 348.723l115.389 115.412c0 0 64.073 21.001 145.657 91.71 34.834 30.191 65.767 77.33 65.767 77.33l-17.815 24.714 63.676 63.51c0 0 13.413-15.937 32.267-43.001 13.45-19.306 26.8-45.333 26.8-45.333s-44.15-101.309-150.8-176c-158.4-110.933-280.94-108.343-280.94-108.343z" />
-<glyph unicode="&#xe61d;" glyph-name="tex" horiz-adv-x="1280" d="M461.383 775.025h-420.203l-12.284-161.303h13.075c9.404 120.809 19.747 141.955 132.585 141.955 13.075 0 34.321 0 40.17 0 13.898-2.18 13.898-11.044 13.898-27.831v-397.002c0-26.358-2.204-34.4-63.501-34.4h-20.657v-17.612c34.909 0.677 71.287 1.385 106.99 1.385 35.585 0 72.082-0.706 106.961-1.385v17.612h-20.305c-60.385 0-62.561 8.041-62.561 34.4v397.002c0 16.11 0 24.855 13.106 27.831h39.935c111.34 0 122.241-21.027 131.643-141.955h13.106zM826.521 304.25h-13.076c-15.955-108.145-25.359-166.929-153.359-166.929h-100.996c-29.061 0-30.443 3.681-30.443 28.774v203.86h68.643c68.643 0 75.196-25.211 75.196-86.764h11.695v189.725h-11.695c0-60.523-6.553-85.262-75.196-85.262h-68.643v180.741c0 24.621 1.381 28.303 30.443 28.303h99.498c112.603 0 125.708-44.854 135.904-141.278h13.106l-17.455 161.303h-368.457v-20.027c51.54 0 59.798 0 59.798-32.78v-393.585c0-32.78-8.14-32.78-59.798-32.78v-17.612h378.683zM1022.693 554.819l107.666 156.002c10.784 15.314 32.705 46.828 92.416 47.622v17.612c-16.66-1.383-44.311-1.383-61.766-1.383-23.978 0-53.833 0-71.964 1.383v-17.612c23.301-2.179 29.033-16.787 29.033-28.538 0-8.718-3.555-14.607-8.726-21.852l-96.059-139.658-107.666 157.947c-5.055 7.952-5.759 10.25-5.759 12.429 0 6.569 7.934 18.994 32.029 19.674v17.612c-23.301-1.383-58.887-1.383-82.865-1.383-18.836 0-55.214 0-72.786 1.383v-17.612c39.964 0 53.040-1.503 69.113-24.149l140.371-206.628-126.59-185.337c-31.236-45.326-78.516-46.119-92.416-46.119v-17.612c16.633 1.385 44.311 1.385 61.766 1.385 19.629 0 53.833 0 71.964-1.385v17.612c-22.509 2.18-29.033 16.787-29.033 28.539 0 9.424 3.555 14.607 7.229 19.791l116.394 170.258 126.59-186.485c5.73-8.069 5.73-10.25 5.73-12.429 0-5.742-6.523-18.29-32-19.791v-17.612c23.301 1.385 58.887 1.385 82.865 1.385 18.836 0 55.214 0 72.875-1.385v17.612c-46.605 0-53.951 3.564-68.407 24.15z" />
-<glyph unicode="&#xe61e;" glyph-name="titres" d="M960 448h-384v-128h128v-384h128v384h128zM64 704h251.75v-768h136.5v768h251.75v128h-640z" />
-<glyph unicode="&#xe61f;" glyph-name="edite" d="M864 960c88.364 0 160-71.634 160-160 0-36.020-11.91-69.258-32-96l-64-64-224 224 64 64c26.742 20.090 59.978 32 96 32zM64 224l-64-288 288 64 592 592-224 224-592-592zM715.578 596.422l-448-448-55.156 55.156 448 448 55.156-55.156z" />
-<glyph unicode="&#xe620;" glyph-name="precedent" d="M576 800v-320l320 320v-704l-320 320v-320l-352 352z" />
-<glyph unicode="&#xe621;" glyph-name="suivant" d="M512 96v320l-320-320v704l320-320v320l352-352z" />
-<glyph unicode="&#xe622;" glyph-name="recherche" d="M992.262 88.604l-242.552 206.294c-25.074 22.566-51.89 32.926-73.552 31.926 57.256 67.068 91.842 154.078 91.842 249.176 0 212.078-171.922 384-384 384-212.076 0-384-171.922-384-384s171.922-384 384-384c95.098 0 182.108 34.586 249.176 91.844-1-21.662 9.36-48.478 31.926-73.552l206.294-242.552c35.322-39.246 93.022-42.554 128.22-7.356s31.892 92.898-7.354 128.22zM384 320c-141.384 0-256 114.616-256 256s114.616 256 256 256 256-114.616 256-256-114.614-256-256-256z" />
-<glyph unicode="&#xe623;" glyph-name="voirtout" d="M512 916c-223.318 0-416.882-130.042-512-320 95.118-189.958 288.682-320 512-320 223.312 0 416.876 130.042 512 320-95.116 189.958-288.688 320-512 320zM764.45 746.296c60.162-38.374 111.142-89.774 149.434-150.296-38.292-60.522-89.274-111.922-149.436-150.296-75.594-48.218-162.89-73.704-252.448-73.704-89.56 0-176.858 25.486-252.452 73.704-60.158 38.372-111.138 89.772-149.432 150.296 38.292 60.524 89.274 111.924 149.434 150.296 3.918 2.5 7.876 4.922 11.86 7.3-9.96-27.328-15.41-56.822-15.41-87.596 0-141.382 114.616-256 256-256s256 114.618 256 256c0 30.774-5.452 60.268-15.408 87.598 3.978-2.378 7.938-4.802 11.858-7.302v0zM512 692c0-53.020-42.98-96-96-96s-96 42.98-96 96c0 53.020 42.98 96 96 96s96-42.982 96-96zM459.588 144.183h142.17v-42.712h-142.17v42.712zM658.299 270.895l230.237 0.407 0.407-45.559-182.237-212.339 182.644 0.407 0.407-39.051-238.373-0.407 0.407 45.559 182.644 211.932h-176.542zM157.241 212.515l-0.767 45.255c0 0 53.692 22.627 111.987 20.71s115.438-36.434 116.589-118.506c1.134-80.922 0-185.238 0-185.238l-48.706-0.384 0.767 44.871c0 0-25.696-43.721-90.126-45.638s-105.083 19.559-110.452 74.019c-5.369 54.459 21.705 97.357 79.771 108.918 41.781 8.319 124.259 4.986 124.259 4.986l-0.384-37.585c0 0-33.908 2.687-83.606 1.918-20.551 0.381-72.215-2.996-73.635-54.459-1.534-55.61 36.093-62.263 59.061-63.664 31.448-1.918 90.51 24.929 93.578 90.126 3.465 73.634 3.42 110.008-29.914 127.711-15.446 8.203-81.010 23.012-148.421-13.040z" />
-<glyph unicode="&#xe624;" glyph-name="accueil" d="M1024 369.556l-512 397.426-512-397.428v162.038l512 397.426 512-397.428zM896 384v-384h-256v256h-256v-256h-256v384l384 288z" />
-<glyph unicode="&#xe625;" glyph-name="imprime" d="M256 896h512v-128h-512v128zM960 704h-896c-35.2 0-64-28.8-64-64v-320c0-35.2 28.794-64 64-64h192v-256h512v256h192c35.2 0 64 28.8 64 64v320c0 35.2-28.8 64-64 64zM128 512c-35.346 0-64 28.654-64 64s28.654 64 64 64 64-28.654 64-64-28.652-64-64-64zM704 64h-384v320h384v-320z" />
-<glyph unicode="&#xe626;" glyph-name="connexion" d="M384 448h-320v128h320v128l192-192-192-192zM1024 960v-832l-384-192v192h-384v256h64v-192h320v576l256 128h-576v-256h-64v320z" />
-<glyph unicode="&#xe627;" glyph-name="deconnexion" d="M768 320v128h-320v128h320v128l192-192zM704 384v-256h-320v-192l-384 192v832h704v-320h-64v256h-512l256-128v-576h256v192z" />
-<glyph unicode="&#xe628;" glyph-name="mail" d="M936.77 812.089h-849.54c-33.511 0-60.682-27.17-60.682-60.682v-606.815c0-33.511 27.17-60.682 60.682-60.682h849.54c33.511 0 60.682 27.17 60.682 60.682v606.815c0 33.511-27.17 60.682-60.682 60.682zM852.918 690.726l-340.918-232.49-340.918 232.49h681.836zM876.089 235.615c0-16.755-13.57-30.34-30.34-30.34h-667.497c-16.771 0-30.34 13.585-30.34 30.34v325.408l333.57-225.926c9.423-5.645 19.972-8.46 30.519-8.46s21.097 2.814 30.519 8.46l333.57 225.926v-325.408z" />
-<glyph unicode="&#xe629;" glyph-name="menu" d="M0.854 962.48h1023.825v-279.787h-1023.825zM0.854 589.429h1023.825v-279.787h-1023.825zM0.854 216.381h1023.825v-279.787h-1023.825z" />
-<glyph unicode="&#xe62a;" glyph-name="cocher" d="M831.815 552.631v-423.844h-635.687v635.687h435.844l104 105.948h-539.844c-58.271 0-105.948-47.677-105.948-105.948v-635.687c0-58.271 47.677-105.948 105.948-105.948h635.687c58.271 0 105.948 47.677 105.948 105.948v529.844zM864.246 887.659l-276.497-282.355-129.032 131.766-92.166-94.118 221.198-225.884 368.663 376.473z" />
-<glyph unicode="&#xe62b;" glyph-name="decocher" d="M827.576 341.376v-211.268h-634.537v634.537h209.268c0 0-31.793 31.007-45.907 45.272-8.429 8.519-7.401 15.556 2.405 26.015 6.946 7.409 35.502 34.469 35.502 34.469h-201.268c-58.166 0-105.756-47.59-105.756-105.756v-634.537c0-58.166 47.59-105.756 105.756-105.756h634.537c58.166 0 105.756 46.505 105.756 104.671v202.353c0 0-25.618-26.344-35.731-37.169s-17.175-10.114-22.988-4.075c-11.737 12.193-47.037 51.244-47.037 51.244zM971.54 502.677c-0.002 0.002-0.004 0.004-0.006 0.005l-155.322 155.325 155.322 155.325c0.002 0.002 0.004 0.003 0.006 0.005 1.672 1.673 2.881 3.627 3.656 5.708 2.123 5.688 0.912 12.341-3.662 16.915l-73.373 73.373c-4.574 4.573-11.225 5.783-16.914 3.66-2.080-0.775-4.035-1.984-5.709-3.655 0-0.002-0.002-0.003-0.004-0.005l-155.324-155.326-155.324 155.325c-0.002 0.002-0.003 0.003-0.005 0.005-1.673 1.671-3.627 2.88-5.707 3.655-5.69 2.124-12.341 0.913-16.915-3.66l-73.374-73.374c-4.574-4.574-5.784-11.226-3.661-16.914 0.776-2.080 1.985-4.036 3.656-5.708 0.002-0.001 0.003-0.003 0.005-0.005l155.325-155.324-155.325-155.326c-0.001-0.002-0.003-0.003-0.004-0.005-1.671-1.673-2.88-3.627-3.657-5.707-2.124-5.688-0.913-12.341 3.661-16.915l73.374-73.373c4.575-4.574 11.226-5.784 16.915-3.661 2.080 0.776 4.035 1.985 5.708 3.656 0.001 0.002 0.003 0.003 0.005 0.005l155.324 155.325 155.324-155.325c0.002-0.001 0.004-0.003 0.006-0.004 1.674-1.672 3.627-2.881 5.707-3.657 5.689-2.123 12.342-0.913 16.914 3.661l73.373 73.374c4.574 4.574 5.785 11.227 3.662 16.915-0.776 2.080-1.985 4.034-3.657 5.707z" />
-<glyph unicode="&#xe62c;" glyph-name="rep" d="M448 832l128-128h448v-704h-1024v832z" />
-<glyph unicode="&#xe62d;" glyph-name="rep-open" d="M832 0l192 512h-832l-192-512zM128 576l-128-576v832h288l128-128h416v-128z" />
-<glyph unicode="&#xe62e;" glyph-name="download" d="M896 448h-160l-224-224-224 224h-160l-128-256v-64h1024v64l-128 256zM0 64h1024v-64h-1024v64zM576 640v256h-128v-256h-224l288-288 288 288h-224z" />
-<glyph unicode="&#xe62f;" glyph-name="minilock" horiz-adv-x="512" d="M411.798 353.763h-10.864v130.355c0 71.879-58.477 130.355-130.355 130.355h-86.903c-71.879 0-130.355-58.477-130.355-130.355v-130.355h-10.864c-17.923 0-32.589-14.665-32.589-32.589v-325.889c0-17.923 14.664-32.589 32.589-32.589h369.34c17.923 0 32.589 14.665 32.589 32.589v325.889c0 17.923-14.665 32.589-32.589 32.589zM140.225 484.118c0 23.959 19.492 43.451 43.451 43.451h86.903c23.959 0 43.451-19.492 43.451-43.451v-130.355h-173.807v130.355z" />
-<glyph unicode="&#xe630;" glyph-name="alphaasc" d="M320 192v768h-128v-768h-160l224-224 224 224h-160zM928-64h-256c-11.8 0-22.644 6.496-28.214 16.9-5.566 10.404-4.958 23.030 1.59 32.85l222.832 334.25h-196.208c-17.672 0-32 14.328-32 32s14.328 32 32 32h256c11.8 0 22.644-6.496 28.214-16.9 5.566-10.404 4.958-23.030-1.59-32.85l-222.83-334.25h196.206c17.672 0 32-14.328 32-32s-14.328-32-32-32zM1020.622 558.314l-192.002 384c-5.42 10.842-16.502 17.69-28.622 17.69-12.122 0-23.202-6.848-28.624-17.69l-191.996-384c-7.904-15.806-1.496-35.030 14.31-42.932 4.594-2.296 9.476-3.386 14.288-3.386 11.736 0 23.040 6.484 28.644 17.698l55.156 110.31h216.446l55.156-110.31c7.902-15.806 27.124-22.21 42.932-14.31 15.808 7.902 22.216 27.124 14.312 42.93zM723.778 704.004l76.22 152.446 76.224-152.446h-152.444z" />
-<glyph unicode="&#xe631;" glyph-name="alphadesc" d="M320 192v768h-128v-768h-160l224-224 224 224h-160zM928 512h-256c-11.8 0-22.644 6.496-28.214 16.9-5.566 10.406-4.958 23.030 1.59 32.85l222.832 334.25h-196.208c-17.672 0-32 14.328-32 32s14.328 32 32 32h256c11.8 0 22.644-6.496 28.214-16.9 5.566-10.406 4.958-23.030-1.59-32.85l-222.83-334.25h196.206c17.672 0 32-14.328 32-32s-14.328-32-32-32zM1020.622-17.69l-192.002 384c-5.42 10.842-16.502 17.69-28.622 17.69-12.122 0-23.202-6.848-28.624-17.69l-191.996-384c-7.904-15.806-1.496-35.030 14.31-42.932 4.594-2.296 9.476-3.386 14.288-3.386 11.736 0 23.040 6.484 28.644 17.698l55.158 110.31h216.446l55.156-110.31c7.902-15.806 27.124-22.21 42.932-14.31 15.806 7.902 22.214 27.124 14.31 42.93zM723.778 128l76.22 152.446 76.226-152.446h-152.446z" />
-<glyph unicode="&#xe632;" glyph-name="chronoasc" d="M320 192v768h-128v-768h-160l224-224 224 224h-160zM802.919 506.985l-126.446 126.448v169.506h76.8v-137.694l103.954-103.952zM714.873 956.539c-169.662 0-307.2-137.538-307.2-307.2s137.538-307.2 307.2-307.2c169.662 0 307.2 137.538 307.2 307.2s-137.538 307.2-307.2 307.2zM714.873 418.939c-127.247 0-230.4 103.153-230.4 230.4s103.153 230.4 230.4 230.4c127.247 0 230.4-103.153 230.4-230.4s-103.153-230.4-230.4-230.4zM886.139 178.11h-126.72v126.72c0 6.362-5.158 11.52-11.52 11.52h-69.12c-6.362 0-11.52-5.158-11.52-11.52v-126.72h-126.72c-6.362 0-11.52-5.158-11.52-11.52v-69.12c0-6.362 5.158-11.52 11.52-11.52h126.72v-126.72c0-6.362 5.158-11.52 11.52-11.52h69.12c6.362 0 11.52 5.158 11.52 11.52v126.72h126.72c6.362 0 11.52 5.158 11.52 11.52v69.12c0 6.362-5.158 11.52-11.52 11.52z" />
-<glyph unicode="&#xe633;" glyph-name="chronodesc" d="M320 192v768h-128v-768h-160l224-224 224 224h-160zM802.919 506.985l-126.446 126.448v169.506h76.8v-137.694l103.954-103.952zM714.873 956.539c-169.662 0-307.2-137.538-307.2-307.2s137.538-307.2 307.2-307.2c169.662 0 307.2 137.538 307.2 307.2s-137.538 307.2-307.2 307.2zM714.873 418.939c-127.247 0-230.4 103.153-230.4 230.4s103.153 230.4 230.4 230.4c127.247 0 230.4-103.153 230.4-230.4s-103.153-230.4-230.4-230.4zM529.019 165.386v-69.12c0-6.362 5.158-11.52 11.52-11.52h345.6c6.362 0 11.52 5.158 11.52 11.52v69.12c0 6.362-5.158 11.52-11.52 11.52h-345.6c-6.362 0-11.52-5.158-11.52-11.52z" />
-<glyph unicode="&#xe634;" glyph-name="ajouterep" d="M856.843 792.843h-344.843c0 63.452-51.496 114.947-114.947 114.947h-229.897c-95.063 0-172.422-77.359-172.422-172.422v-574.743c0-95.063 77.359-172.422 172.422-172.422h689.691c95.063 0 172.422 77.359 172.422 172.422v459.794c0 95.063-77.359 172.422-172.422 172.422zM856.843 103.157h-689.691c-31.726 0-57.475 25.748-57.475 57.475v402.319h229.897c15.805 0 28.738 12.931 28.738 28.738s-12.931 28.738-28.738 28.738h-229.897v114.947c0 31.726 25.748 57.475 57.475 57.475h229.897c0-63.452 51.496-114.947 114.947-114.947h344.843c31.726 0 57.475-25.748 57.475-57.475h-229.897c-15.805 0-28.738-12.931-28.738-28.738s12.931-28.738 28.738-28.738h229.897v-402.319c0-31.726-25.748-57.475-57.475-57.475zM684.422 448h-114.947v114.947c0 31.783-25.69 57.475-57.475 57.475s-57.475-25.69-57.475-57.475v-114.947h-114.947c-31.783 0-57.475-25.69-57.475-57.475s25.69-57.475 57.475-57.475h114.947v-114.947c0-31.783 25.69-57.475 57.475-57.475s57.475 25.69 57.475 57.475v114.947h114.947c31.783 0 57.475 25.69 57.475 57.475s-25.69 57.475-57.475 57.475z" />
-<glyph unicode="&#xe635;" glyph-name="ajoutedoc" d="M684.422 448h-114.947v114.947c0 31.783-25.69 57.475-57.475 57.475s-57.475-25.69-57.475-57.475v-114.947h-114.947c-31.783 0-57.475-25.69-57.475-57.475s25.69-57.475 57.475-57.475h114.947v-114.947c0-31.783 25.69-57.475 57.475-57.475s57.475 25.69 57.475 57.475v114.947h114.947c31.783 0 57.475 25.69 57.475 57.475s-25.69 57.475-57.475 57.475zM954.952 718.53l-229.897 229.897c-10.748 10.804-25.347 16.84-40.635 16.84h-459.794c-95.063 0-172.422-77.359-172.422-172.422v-689.691c0-95.063 77.359-172.422 172.422-172.422h574.743c95.063 0 172.422 77.359 172.422 172.422v574.743c0 15.287-6.034 29.887-16.84 40.635zM833.051 677.897h-62.418c-47.53 0-86.213 38.679-86.213 86.213v62.418l148.629-148.629zM799.371 45.681h-574.743c-31.726 0-57.475 25.748-57.475 57.475v689.691c0 31.726 25.748 57.475 57.475 57.475h402.319v-86.213c0-79.255 64.429-143.685 143.685-143.685h86.213v-517.268c0-31.726-25.748-57.475-57.475-57.475z" />
-<glyph unicode="&#xe636;" glyph-name="doc" d="M917.806 730.924c-22.212 30.292-53.174 65.7-87.178 99.704s-69.412 64.964-99.704 87.178c-51.574 37.82-76.592 42.194-90.924 42.194h-496c-44.112 0-80-35.888-80-80v-864c0-44.112 35.888-80 80-80h736c44.112 0 80 35.888 80 80v624c0 14.332-4.372 39.35-42.194 90.924zM785.374 785.374c30.7-30.7 54.8-58.398 72.58-81.374h-153.954v153.946c22.984-17.78 50.678-41.878 81.374-72.572zM896 16c0-8.672-7.328-16-16-16h-736c-8.672 0-16 7.328-16 16v864c0 8.672 7.328 16 16 16 0 0 495.956 0.002 496 0v-224c0-17.672 14.326-32 32-32h224v-624z" />
-<glyph unicode="&#xe637;" glyph-name="doc-pdf" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM583.999 348q18.857-14.857 48-32 33.714 4 66.857 4 84 0 101.143-28 9.143-12.571 1.143-29.714 0-0.571-0.571-1.143l-1.143-1.143v-0.571q-3.429-21.714-40.571-21.714-27.429 0-65.714 11.429t-74.286 30.286q-126.286-13.714-224-47.429-87.429-149.714-138.286-149.714-8.571 0-16 4l-13.714 6.857q-0.571 0.571-3.429 2.857-5.714 5.714-3.429 20.571 5.143 22.857 32 52.286t75.429 55.143q8 5.143 13.143-3.429 1.143-1.143 1.143-2.286 29.714 48.571 61.143 112.571 38.857 77.714 59.429 149.714-13.714 46.857-17.429 91.143t3.714 72.857q6.286 22.857 24 22.857h12.571q13.143 0 20-8.571 10.286-12 5.143-38.857-1.143-3.429-2.286-4.571 0.571-1.714 0.571-4.571v-17.143q-1.143-70.286-8-109.714 31.429-93.714 83.429-136zM254.856 113.143q29.714 13.714 78.286 90.286-29.143-22.857-50-48t-28.286-42.286zM482.285 638.857q-8.571-24-1.143-75.429 0.571 4 4 25.143 0 1.714 4 24.571 0.571 2.286 2.286 4.571-0.571 0.571-0.571 1.143t-0.286 0.857-0.286 0.857q-0.571 12.571-7.429 20.571 0-0.571-0.571-1.143v-1.143zM411.428 261.143q77.143 30.857 162.286 46.286-1.143 0.571-7.429 5.429t-9.143 7.714q-43.429 38.286-72.571 100.571-15.429-49.143-47.429-112.571-17.143-32-25.714-47.429zM780.571 270.286q-13.714 13.714-80 13.714 43.429-16 70.857-16 8 0 10.286 0.571 0 0.571-1.143 1.714z" />
-<glyph unicode="&#xe638;" glyph-name="doc-doc" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM206.285 521.143v-61.143h40l93.714-377.714h90.857l73.143 277.143q4 11.429 5.714 26.286 1.143 9.143 1.143 13.714h2.286l1.714-13.714q0.571-1.714 2-11.429t3.143-14.857l73.143-277.143h90.857l93.714 377.714h40v61.143h-171.429v-61.143h51.429l-56.571-250.286q-2.857-11.429-4-26.286l-1.143-12h-2.286l-1.714 12q-0.571 2.857-2.286 12t-2.857 14.286l-82.286 311.429h-65.143l-82.286-311.429q-1.143-5.143-2.571-14t-2-12.286l-2.286-12h-2.286l-1.143 12q-1.143 14.857-4 26.286l-56.571 250.286h51.429v61.143h-171.429z" />
-<glyph unicode="&#xe639;" glyph-name="doc-xls" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM318.285 142.857v-60.571h160.571v60.571h-42.857l58.857 92q2.857 4 5.714 9.429t4.286 7.714 2 2.286h1.143q0.571-2.286 2.857-5.714 1.143-2.286 2.571-4.286t3.429-4.571 3.714-4.857l61.143-92h-43.429v-60.571h166.286v60.571h-38.857l-109.714 156 111.429 161.143h38.286v61.143h-159.429v-61.143h42.286l-58.857-90.857q-2.286-4-5.714-9.429t-5.143-7.714l-1.143-1.714h-1.143q-0.571 2.286-2.857 5.714-3.429 6.286-9.714 13.143l-60.571 90.857h43.429v61.143h-165.714v-61.143h38.857l108-155.429-110.857-161.714h-38.857z" />
-<glyph unicode="&#xe63a;" glyph-name="doc-ppt" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM310.856 142.857v-60.571h186.857v60.571h-53.143v95.429h78.286q43.429 0 67.429 8.571 38.286 13.143 60.857 49.714t22.571 83.429q0 46.286-21.143 80.571t-57.143 49.714q-27.429 10.857-74.286 10.857h-210.286v-61.143h52.571v-317.143h-52.571zM512.571 302.857h-68v153.143h68.571q29.714 0 47.429-10.286 32-18.857 32-65.714 0-50.857-35.429-68.571-17.714-8.571-44.571-8.571z" />
-<glyph unicode="&#xe63b;" glyph-name="doc-jpg" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM804.571 265.143v-182.857h-585.143v109.714l109.714 109.714 73.143-73.143 219.429 219.429zM329.142 374.857q-45.714 0-77.714 32t-32 77.714 32 77.714 77.714 32 77.714-32 32-77.714-32-77.714-77.714-32z" />
-<glyph unicode="&#xe63c;" glyph-name="doc-zip" d="M438.856 740.571v73.143h-73.143v-73.143h73.143zM511.999 667.429v73.143h-73.143v-73.143h73.143zM438.856 594.286v73.143h-73.143v-73.143h73.143zM511.999 521.143v73.143h-73.143v-73.143h73.143zM911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-73.143v-73.143h-73.143v73.143h-292.571v-877.714h731.429zM519.428 421.143l61.143-199.429q4.571-15.429 4.571-29.714 0-47.429-41.429-78.571t-104.857-31.143-104.857 31.143-41.429 78.571q0 14.286 4.571 29.714 12 36 68.571 226.286v73.143h73.143v-73.143h45.143q12.571 0 22.286-7.429t13.143-19.429zM438.856 155.429q30.286 0 51.714 10.857t21.429 25.714-21.429 25.714-51.714 10.857-51.714-10.857-21.429-25.714 21.429-25.714 51.714-10.857z" />
-<glyph unicode="&#xe63d;" glyph-name="doc-mp3" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM427.428 474.286q11.429-4.571 11.429-17.143v-310.857q0-12.571-11.429-17.143-4.571-1.143-6.857-1.143-6.857 0-13.143 5.143l-94.857 95.429h-74.857q-8 0-13.143 5.143t-5.143 13.143v109.714q0 8 5.143 13.143t13.143 5.143h74.857l94.857 95.429q9.143 8.571 20 4zM665.713 80.571q17.714 0 28.571 13.714 73.714 90.857 73.714 207.429t-73.714 207.429q-9.143 12-24.571 13.714t-26.857-8q-12-9.714-13.429-24.857t8.286-27.143q57.143-70.286 57.143-161.143t-57.143-161.143q-9.714-12-8.286-27.143t13.429-24.286q10.286-8.571 22.857-8.571zM545.142 165.143q15.429 0 26.857 11.429 49.714 53.143 49.714 125.143t-49.714 125.143q-10.286 10.857-25.714 11.429t-26.286-9.714-11.429-25.429 10.286-26.571q29.714-32.571 29.714-74.857t-29.714-74.857q-10.857-11.429-10.286-26.571t11.429-25.429q11.429-9.714 25.143-9.714z" />
-<glyph unicode="&#xe63e;" glyph-name="doc-mp4" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM511.999 521.143q29.714 0 51.429-21.714t21.714-51.429v-219.429q0-29.714-21.714-51.429t-51.429-21.714h-219.429q-29.714 0-51.429 21.714t-21.714 51.429v219.429q0 29.714 21.714 51.429t51.429 21.714h219.429zM793.142 520q11.429-4.571 11.429-17.143v-329.143q0-12.571-11.429-17.143-4.571-1.143-6.857-1.143-8 0-13.143 5.143l-151.429 152v51.429l151.429 152q5.143 5.143 13.143 5.143 2.286 0 6.857-1.143z" />
-<glyph unicode="&#xe63f;" glyph-name="doc-pyt" d="M911.999 742.857q16-16 27.429-43.429t11.429-50.286v-658.286q0-22.857-16-38.857t-38.857-16h-768q-22.857 0-38.857 16t-16 38.857v914.286q0 22.857 16 38.857t38.857 16h512q22.857 0 50.286-11.429t43.429-27.429zM658.285 882.286v-214.857h214.857q-5.714 16.571-12.571 23.429l-178.857 178.857q-6.857 6.857-23.429 12.571zM877.713 9.143v585.143h-237.714q-22.857 0-38.857 16t-16 38.857v237.714h-438.857v-877.714h731.429zM347.428 521.143q4.571 6.286 12 7.143t13.714-3.714l29.143-21.714q6.286-4.571 7.143-12t-3.714-13.714l-104-138.857 104-138.857q4.571-6.286 3.714-13.714t-7.143-12l-29.143-21.714q-6.286-4.571-13.714-3.714t-12 7.143l-129.143 172q-8 10.857 0 21.714zM805.713 349.143q8-10.857 0-21.714l-129.143-172q-4.571-6.286-12-7.143t-13.714 3.714l-29.143 21.714q-6.286 4.571-7.143 12t3.714 13.714l104 138.857-104 138.857q-4.571 6.286-3.714 13.714t7.143 12l29.143 21.714q6.286 4.571 13.714 3.714t12-7.143zM451.428 85.714q-7.429 1.143-11.714 7.429t-3.143 13.714l78.857 474.857q1.143 7.429 7.429 11.714t13.714 3.143l36-5.714q7.429-1.143 11.714-7.429t3.143-13.714l-78.857-474.857q-1.143-7.429-7.429-11.714t-13.714-3.143z" />
-<glyph unicode="&#xe640;" glyph-name="rss" d="M136.294 209.070c-75.196 0-136.292-61.334-136.292-136.076 0-75.154 61.1-135.802 136.292-135.802 75.466 0 136.494 60.648 136.494 135.802-0.002 74.742-61.024 136.076-136.494 136.076zM0.156 612.070v-196.258c127.784 0 247.958-49.972 338.458-140.512 90.384-90.318 140.282-211.036 140.282-339.3h197.122c-0.002 372.82-303.282 676.070-675.862 676.070zM0.388 960v-196.356c455.782 0 826.756-371.334 826.756-827.644h196.856c0 564.47-459.254 1024-1023.612 1024z" />
-<glyph unicode="&#xe641;" glyph-name="infos" d="M448 656c0 26.4 21.6 48 48 48h32c26.4 0 48-21.6 48-48v-32c0-26.4-21.6-48-48-48h-32c-26.4 0-48 21.6-48 48v32zM640 192h-256v64h64v192h-64v64h192v-256h64zM512 960c-282.77 0-512-229.23-512-512s229.23-512 512-512 512 229.23 512 512-229.23 512-512 512zM512 32c-229.75 0-416 186.25-416 416s186.25 416 416 416 416-186.25 416-416-186.25-416-416-416z" />
-<glyph unicode="&#xe642;" glyph-name="colles" d="M8.192 895.488c-7.168-7.168-8.192-47.104-8.192-365.056 0-326.656 0.512-358.4 8.704-364.544 5.12-4.608 23.552-7.168 52.224-7.68 24.064-0.512 44.544-1.024 44.544-1.536 0.512 0-3.584-14.848-9.216-32.256-5.632-17.92-10.24-39.936-9.728-49.664 1.024-41.472 46.592-70.144 86.528-53.76 9.216 3.584 15.36 4.608 13.824 2.048-6.144-10.24 7.68-25.6 23.552-25.6 18.432 0 20.992 5.12 32.256 69.12 31.744 181.76 33.792 193.536 28.672 199.68-8.192 9.728-24.064 12.288-32.768 5.632-7.168-5.632-43.52-100.864-64.512-171.008-9.728-32.768-12.8-36.864-23.552-36.864-24.064 0-23.040 7.168 11.264 115.2 10.24 31.232 26.112 72.704 35.328 92.16 14.336 29.696 20.992 38.4 39.424 48.64 22.016 12.288 23.552 12.288 159.232 12.8h137.216l58.88 70.656c32.256 38.4 61.952 70.144 65.536 70.144 9.728 0 19.968-13.824 16.896-22.528-2.56-6.144-90.112-113.664-116.736-142.336-6.144-7.168-16.896-9.216-54.272-9.728-65.536-0.512-66.56-2.048-52.736-73.728 6.656-33.28 8.192-41.472 12.8-69.12 2.048-12.8 4.608-27.648 6.144-33.28 1.024-5.632 6.144-34.304 11.776-63.488 9.728-54.272 14.336-61.952 34.816-61.952 18.944 0 22.016 17.92 10.752 72.192-5.12 26.624-10.752 57.344-12.288 68.608l-3.072 20.48 244.736-1.024c165.888-0.512 248.32 1.024 256.512 5.12l11.264 5.12v362.496c0 353.28 0 363.008-9.728 368.128-6.656 3.584-173.568 5.12-504.32 5.12-442.368 0-494.592-1.024-501.76-8.192zM976.896 530.944l-1.536-326.144h-474.112l-3.072 18.944c-1.536 10.752-2.56 20.992-2.048 23.040 0 2.56 12.8 4.096 28.672 4.608 15.36 0.512 34.304 3.584 43.008 7.168 19.456 8.192 144.896 158.208 151.040 181.248 6.144 22.528 0.512 42.496-16.896 59.904-18.432 18.432-37.376 23.040-62.464 15.36-15.872-4.608-28.16-15.872-59.392-53.248-21.504-26.112-45.568-54.784-53.76-64.512l-15.36-17.408-131.072-0.512c-123.904-0.512-133.12-1.536-154.624-11.776-43.008-20.48-58.368-40.96-86.016-112.128l-19.456-50.176h-35.328l-35.84-0.512-1.024 326.144-1.536 325.632h931.84l-1.024-325.632zM407.040 766.464c-25.088-2.56-35.84-23.552-19.968-38.912 6.656-7.168 29.184-8.192 168.448-8.192h161.28l7.68 12.288c9.728 14.336 5.632 27.648-9.728 31.232-12.288 3.072-284.16 6.144-307.712 3.584zM533.504 641.536c-7.68-7.68-7.68-26.112 0-33.792 8.704-8.704 393.728-8.704 402.432 0 7.68 7.68 7.68 26.112 0 33.792-8.704 8.704-393.728 8.704-402.432 0zM335.36 621.568c-26.624-6.144-40.448-13.312-57.344-31.232-69.12-72.192-21.504-185.344 77.824-185.344 69.12 0 119.296 60.416 107.52 130.048-4.096 24.576-29.184 59.392-51.712 72.704-20.48 11.776-56.832 18.432-76.288 13.824zM399.872 556.544c37.888-42.496 11.264-105.984-44.032-104.96-26.624 0-41.472 8.192-53.76 28.672-17.92 29.184-9.216 69.12 19.456 87.040 22.016 14.336 60.416 9.216 78.336-10.752z" />
-<glyph unicode="&#xe643;" glyph-name="recent" d="M728.992 448c137.754 87.334 231.008 255.208 231.008 448 0 21.676-1.192 43.034-3.478 64h-889.042c-2.29-20.968-3.48-42.326-3.48-64 0-192.792 93.254-360.666 231.006-448-137.752-87.334-231.006-255.208-231.006-448 0-21.676 1.19-43.034 3.478-64h889.042c2.288 20.966 3.478 42.324 3.478 64 0.002 192.792-93.252 360.666-231.006 448zM160 0c0 186.912 80.162 345.414 224 397.708v100.586c-143.838 52.29-224 210.792-224 397.706v0h704c0-186.914-80.162-345.416-224-397.706v-100.586c143.838-52.294 224-210.796 224-397.708h-704zM619.626 290.406c-71.654 40.644-75.608 93.368-75.626 125.366v64.228c0 31.994 3.804 84.914 75.744 125.664 38.504 22.364 71.808 56.348 97.048 98.336h-409.582c25.266-42.032 58.612-76.042 97.166-98.406 71.654-40.644 75.606-93.366 75.626-125.366v-64.228c0-31.992-3.804-84.914-75.744-125.664-72.622-42.18-126.738-125.684-143.090-226.336h501.67c-16.364 100.708-70.53 184.248-143.212 226.406z" />
-<glyph unicode="&#xe644;" glyph-name="lock1" d="M443.75 960c-112.928 0-204.813-91.885-204.813-204.813v-204.813h-17.063c-28.16 0-51.188-23.027-51.188-51.188v-512c0-28.16 23.028-51.188 51.188-51.188h580.25c28.16 0 51.188 23.028 51.188 51.188v512c0 28.16-23.028 51.188-51.188 51.188h-17.063v204.813c0 112.928-91.885 204.813-204.813 204.813h-136.5zM443.75 823.437h136.5c37.644 0 68.25-30.608 68.25-68.25v-204.813h-273.063v204.813c0 37.644 30.671 68.25 68.313 68.25zM537.188 500.187h64.563v-526.625h-91.938v403.5c-13.68-10.64-30.914-20.992-51.688-31.125s-40.809-18.476-60.063-25.063l-28.125 69.875c29.387 11.653 58.801 26.635 88.188 44.875 29.893 18.24 56.262 39.735 79.063 64.563z" />
-<glyph unicode="&#xe645;" glyph-name="lock2" d="M443.75 960c-112.928 0-204.813-91.885-204.813-204.813v-204.813h-17.063c-28.16 0-51.188-23.027-51.188-51.188v-512c0-28.16 23.028-51.188 51.188-51.188h580.25c28.16 0 51.188 23.028 51.188 51.188v512c0 28.16-23.028 51.188-51.188 51.188h-17.063v204.813c0 112.928-91.885 204.813-204.813 204.813h-136.5zM443.75 823.437h136.5c37.644 0 68.25-30.608 68.25-68.25v-204.813h-273.063v204.813c0 37.644 30.671 68.25 68.313 68.25zM505.188 512.375c56.24-0.001 97.528-13.46 123.875-40.313 26.853-26.347 40.25-62.519 40.25-108.625 0-18.24-3.775-36.267-11.375-54-7.6-17.227-17.528-34.155-29.688-50.875-11.654-16.214-25.050-32.231-40.25-47.938-15.2-15.2-30.425-30.119-45.625-44.813-8.107-7.6-17.179-16.735-27.313-27.375s-19.755-21.235-28.875-31.875c-9.12-10.64-16.976-21.054-23.563-31.188-6.587-9.627-10.181-17.726-10.688-24.313h234.125v-77.5h-335.188c-0.507 4.053-0.75 8.864-0.75 14.438 0 6.080 0 10.585 0 13.625 0 24.32 3.775 46.671 11.375 66.938 8.107 20.773 18.521 40.017 31.188 57.75s26.856 34.418 42.563 50.125c15.707 15.706 31.418 31.175 47.125 46.375 12.16 11.653 23.791 23.041 34.938 34.188s20.768 22.047 28.875 32.688c8.613 11.146 15.496 22.29 20.563 33.438 5.066 11.653 7.562 23.59 7.563 35.75 0 26.346-7.613 45.040-22.813 56.188s-33.651 16.75-55.438 16.75c-14.187 0-27.403-2.010-39.563-6.063s-23.061-8.865-32.688-14.438c-9.12-5.574-17.219-11.42-24.313-17.5-7.093-5.574-12.391-10.141-15.938-13.688l-45.625 64.625c21.28 20.266 46.127 36.464 74.5 48.625 28.88 12.666 59.817 18.999 92.75 19z" />
-<glyph unicode="&#xe646;" glyph-name="lock3" d="M443.75 960c-112.928 0-204.813-91.885-204.813-204.813v-204.813h-17.063c-28.16 0-51.188-23.027-51.188-51.188v-512c0-28.16 23.028-51.188 51.188-51.188h580.25c28.16 0 51.188 23.028 51.188 51.188v512c0 28.16-23.028 51.188-51.188 51.188h-17.063v204.813c0 112.928-91.885 204.813-204.813 204.813h-136.5zM443.75 823.437h136.5c37.644 0 68.25-30.608 68.25-68.25v-204.813h-273.063v204.813c0 37.644 30.671 68.25 68.313 68.25zM492.313 512.375c29.386-0.001 54.72-3.532 76-10.625s38.757-17.265 52.438-30.438c14.186-12.667 24.6-27.83 31.188-45.563 7.093-17.227 10.625-36.227 10.625-57 0-24.32-6.82-46.122-20.5-65.375-13.174-19.254-30.408-33.929-51.688-44.063 27.36-9.627 49.891-25.582 67.625-47.875 18.24-22.294 27.375-50.915 27.375-85.875 0-23.307-4.081-45.108-12.188-65.375-8.107-19.76-20.53-36.994-37.25-51.688-16.72-14.187-37.973-25.574-63.813-34.188-25.334-8.107-55.721-12.187-91.188-12.188-13.68 0-27.869 1.036-42.563 3.063-14.187 1.52-27.889 3.773-41.063 6.813-12.667 2.533-24.298 5.335-34.938 8.375-10.64 3.547-18.739 6.835-24.313 9.875l18.188 78.313c10.64-5.067 26.108-10.913 46.375-17.5 20.267-6.080 45.357-9.125 75.25-9.125 40.026 0 68.891 7.612 86.625 22.813 17.733 15.707 26.625 36.472 26.625 62.313 0 16.72-3.532 30.666-10.625 41.813-6.587 11.146-15.965 19.976-28.125 26.563-11.654 7.093-25.356 11.904-41.063 14.438-15.2 3.040-31.399 4.562-48.625 4.563h-31.188v74.5h38c11.653 0 23.346 1.036 35 3.063 12.16 2.533 23.061 6.551 32.688 12.125 9.626 6.080 17.482 13.935 23.563 23.563s9.062 22.050 9.063 37.25c0 12.16-2.253 22.511-6.813 31.125s-10.65 15.739-18.25 21.313c-7.094 5.573-15.436 9.654-25.063 12.188s-19.798 3.75-30.438 3.75c-22.8 0-43.017-3.532-60.75-10.625-17.733-6.587-33.445-14.2-47.125-22.813l-33.438 68.438c7.093 4.56 15.679 9.37 25.813 14.438 10.133 5.066 21.277 9.877 33.438 14.438 12.667 4.559 26.126 8.091 40.313 10.625 14.187 3.039 29.106 4.562 44.813 4.563z" />
-<glyph unicode="&#xe647;" glyph-name="lock4" d="M443.75 960c-112.928 0-204.813-91.885-204.813-204.813v-204.813h-17.063c-28.16 0-51.188-23.027-51.188-51.188v-512c0-28.16 23.028-51.188 51.188-51.188h580.25c28.16 0 51.188 23.028 51.188 51.188v512c0 28.16-23.028 51.188-51.188 51.188h-17.063v204.813c0 112.928-91.885 204.813-204.813 204.813h-136.5zM443.75 823.437h136.5c37.644 0 68.25-30.608 68.25-68.25v-204.813h-273.063v204.813c0 37.644 30.671 68.25 68.313 68.25zM559.938 500.187h87.438v-325.25h59.25v-75.25h-59.25v-126.125h-89.688v126.125h-231.063v65.375c10.133 22.293 23.592 47.87 40.313 76.75 17.227 28.88 36.227 58.537 57 88.938s42.818 60.3 66.125 89.688c23.306 29.386 46.568 55.936 69.875 79.75zM557.688 387c-12.16-14.694-24.827-30.405-38-47.125-12.667-16.72-25.090-34.198-37.25-52.438s-23.791-36.997-34.938-56.25c-11.147-18.747-21.318-37.504-30.438-56.25h140.625v212.063z" />
-<glyph unicode="&#xe648;" glyph-name="lock5" d="M443.75 960c-112.928 0-204.813-91.885-204.813-204.813v-204.813h-17.063c-28.16 0-51.188-23.027-51.188-51.188v-512c0-28.16 23.028-51.188 51.188-51.188h580.25c28.16 0 51.188 23.028 51.188 51.188v512c0 28.16-23.028 51.188-51.188 51.188h-17.063v204.813c0 112.928-91.885 204.813-204.813 204.813h-136.5zM443.75 823.437h136.5c37.644 0 68.25-30.608 68.25-68.25v-204.813h-273.063v204.813c0 37.644 30.671 68.25 68.313 68.25zM398.063 500.187h269.063v-77.5h-190.75c-0.507-8.614-1.299-18.479-2.313-29.625-0.507-10.64-1.237-21.541-2.25-32.688-0.507-11.147-1.299-21.805-2.313-31.938s-1.987-18.72-3-25.813c74.986-4.054 130.221-21.288 165.688-51.688 35.973-29.894 53.937-70.939 53.938-123.125 0-23.813-4.081-45.858-12.188-66.125s-20.468-37.744-37.188-52.438c-16.72-14.693-37.792-26.324-63.125-34.938-25.334-8.107-54.929-12.187-88.875-12.188-13.68 0-27.626 1.036-41.813 3.063s-27.889 4.523-41.063 7.563c-12.667 2.533-24.054 5.335-34.188 8.375s-17.746 5.842-22.813 8.375l17.5 77.5c10.64-5.067 25.802-10.608 45.563-16.688 20.267-5.573 44.87-8.375 73.75-8.375 19.76 0 36.751 2.009 50.938 6.063 14.186 4.56 25.574 10.65 34.188 18.25 9.12 7.6 15.696 16.186 19.75 25.813 4.053 10.133 6.062 20.791 6.063 31.938 0 16.72-3.289 31.701-9.875 44.875s-18.218 24.317-34.938 33.438c-16.214 9.12-38.259 15.94-66.125 20.5-27.36 4.56-62.072 6.812-104.125 6.813 5.573 48.64 9.897 94.801 12.938 138.375 3.040 44.080 5.536 88.107 7.563 132.188z" />
-<glyph unicode="&#xe649;" glyph-name="agenda" d="M320 576h128v-128h-128zM512 576h128v-128h-128zM704 576h128v-128h-128zM128 192h128v-128h-128zM320 192h128v-128h-128zM512 192h128v-128h-128zM320 384h128v-128h-128zM512 384h128v-128h-128zM704 384h128v-128h-128zM128 384h128v-128h-128zM832 960v-64h-128v64h-448v-64h-128v64h-128v-1024h960v1024h-128zM896 0h-832v704h832v-704z" />
-<glyph unicode="&#xe64a;" glyph-name="ajout-colle" d="M992 576h-352v352c0 17.672-14.328 32-32 32h-192c-17.672 0-32-14.328-32-32v-352h-352c-17.672 0-32-14.328-32-32v-192c0-17.672 14.328-32 32-32h352v-352c0-17.672 14.328-32 32-32h192c17.672 0 32 14.328 32 32v352h352c17.672 0 32 14.328 32 32v192c0 17.672-14.328 32-32 32zM958.454 190.145c0 0-24.773 46.503-83.81 47.377-36.65 0.543-102.27-30.681-102.19-112.544 0.084-86.010 69.942-113.203 102.686-112.398 27.915 0.686 61.171 12.84 84.039 48.86 0.229-22.411-0.509-46.731 0.108-69.597-23.462-14.295-50.084-34.075-104.461-31.33-85.844 4.334-149.030 79.244-149.945 165.399-1.114 104.9 86.806 157.013 130.992 162.992 61.646 8.341 102.132-15.219 122.256-31.709 0.274-38.882 0.323-67.049 0.323-67.049z" />
-<glyph unicode="&#xe64b;" glyph-name="messages" horiz-adv-x="1152" d="M480 832c-50.666 0-99.582-7.95-145.386-23.628-42.924-14.694-81.114-35.436-113.502-61.646-60.044-48.59-93.112-110.802-93.112-175.174 0-35.99 10.066-70.948 29.92-103.898 20.686-34.34 51.898-65.794 90.26-90.958 30.44-19.968 50.936-51.952 56.362-87.95 0.902-5.99 1.63-12.006 2.18-18.032 2.722 2.52 5.424 5.114 8.114 7.794 24.138 24.040 56.688 37.312 90.322 37.312 5.348 0 10.718-0.336 16.094-1.018 19.36-2.452 39.124-3.696 58.748-3.696 50.666 0 99.58 7.948 145.384 23.628 42.926 14.692 81.116 35.434 113.504 61.644 60.046 48.59 93.112 110.802 93.112 175.174s-33.066 126.582-93.112 175.174c-32.388 26.212-70.578 46.952-113.504 61.646-45.804 15.678-94.718 23.628-145.384 23.628zM480 960v0c265.096 0 480-173.914 480-388.448s-214.904-388.448-480-388.448c-25.458 0-50.446 1.62-74.834 4.71-103.106-102.694-222.172-121.108-341.166-123.814v25.134c64.252 31.354 116 88.466 116 153.734 0 9.106-0.712 18.048-2.030 26.794-108.558 71.214-177.97 179.988-177.97 301.89 0 214.534 214.904 388.448 480 388.448zM996 89.314c0-55.942 36.314-104.898 92-131.772v-21.542c-103.126 2.318-197.786 18.102-287.142 106.126-21.14-2.65-42.794-4.040-64.858-4.040-95.47 0-183.408 25.758-253.614 69.040 144.674 0.506 281.26 46.854 384.834 130.672 52.208 42.252 93.394 91.826 122.414 147.348 30.766 58.866 46.366 121.582 46.366 186.406 0 10.448-0.45 20.836-1.258 31.168 72.57-59.934 117.258-141.622 117.258-231.676 0-104.488-60.158-197.722-154.24-258.764-1.142-7.496-1.76-15.16-1.76-22.966z" />
-<glyph unicode="&#xe64c;" glyph-name="lock" d="M802.133 550.396h-17.067v204.8c0 112.928-91.872 204.8-204.8 204.8h-136.533c-112.928 0-204.8-91.872-204.8-204.8v-204.8h-17.067c-28.16 0-51.2-23.040-51.2-51.2v-511.999c0-28.16 23.040-51.2 51.2-51.2h580.266c28.16 0 51.2 23.040 51.2 51.2v511.999c0 28.16-23.040 51.2-51.2 51.2zM375.467 755.195c0 37.643 30.624 68.267 68.267 68.267h136.533c37.643 0 68.267-30.624 68.267-68.267v-204.8h-273.066v204.8z" />
-<glyph unicode="&#xe64d;" glyph-name="locktotal" d="M443.73 959.996c-112.928 0-204.797-91.873-204.797-204.801v-204.801h-17.070c-28.16 0-51.199-23.039-51.199-51.199v-512c0-28.16 23.039-51.199 51.199-51.199h580.266c28.16 0 51.199 23.039 51.199 51.199v512c0 28.159-23.037 51.197-51.195 51.199h-17.066v204.801c0 112.928-91.873 204.801-204.801 204.801h-136.535zM443.73 823.461h136.535c37.644 0 68.266-30.624 68.266-68.266v-204.801h-273.066v204.801c0 37.644 30.624 68.266 68.266 68.266zM468.648 500.219l98.047-0.012 0.406-183.074c0 0-1.107-31.94-8.133-106.848-3.334-35.552-8.242-72.605-8.242-72.605l-65.363 0.023c0 0-5.242 35.191-8.898 72.656-7.194 73.722-8.359 107.48-8.359 107.48l0.543 182.379zM517.496 85c0.001 0 0.003 0 0.004 0 33.687 0 60.996-27.306 61-60.992v0l-61-0.008h61c0-33.689-27.311-61-61-61v0c-33.688 0-60.998 27.308-61 60.996v0c0 0.001 0 0.003 0 0.004 0 33.688 27.308 60.998 60.996 61v0z" />
-<glyph unicode="&#xe64e;" glyph-name="editemultiple" d="M864 960c88.364 0 160-71.634 160-160 0-36.020-11.91-69.258-32-96l-64-64-224 224 64 64c26.742 20.090 59.978 32 96 32zM64 224l-64-288 288 64 592 592-224 224-592-592zM715.578 596.422l-448-448-55.156 55.156 448 448 55.156-55.156zM944.814 322.508h-266.847c-24.461 0-44.475-20.014-44.475-44.475v-266.847c0-24.461 20.014-44.475 44.475-44.475h266.847c24.461 0 44.475 20.014 44.475 44.475v266.847c0 24.461-20.014 44.475-44.475 44.475zM789.153 46.45l-82.436 82.436 31.448 31.448 50.987-50.987 106.581 106.581 31.448-31.448-138.029-138.030z" />
-<glyph unicode="&#xe64f;" glyph-name="plie" d="M192 832l640-384-640-384z" />
-<glyph unicode="&#xe650;" glyph-name="deplie" d="M896 768l-384-640-384 640z" />
-<glyph unicode="&#xe651;" glyph-name="mailenvoi" d="M676.492 846.799c-90.915 0.283-185.555-6.515-268.293-46.484-24.502-12.035-45.499-27.879-65.255-46.963-14.314-17.746-27.432-37.053-32.001-59.338-12.987-48.33 5.401-98.475 33.969-137.396 21.042-27.609 46.976-53.198 75.537-73.1 8.291-9.673 16.518-9.686 2.47 3.519-28.78 35.785-50.875 83.78-37.505 130.735 6.129 17.822 16.229 32.511 31.361 44.655 26.584 23.498 62.119 34.629 96.34 42.864 53.562 12.261 108.689 13.459 163.376 13.144 0.151-20.822-0.385-64.435 0.33-85.246 97.622 40.596 223.369 108.5 320.381 150.563-96.929 43.986-223.634 105.626-320.997 148.621-0.324-28.524 0.286-57.035 0.286-85.574zM75.9 630.639c-0.3-0.202-1.9-0.605-3.7-1.009-21.5-3.734-41.8-25.027-45-46.925-0.4-3.027-0.7-135.226-0.6-293.662l0.1-288.112 2.1-6.559c4.3-13.321 13-24.522 24.7-31.99 4.5-2.927 8.3-4.743 11-5.348 0.6-0.101 1.8-0.605 2.7-1.11s3.4-1.211 5.5-1.615c2.1-0.505 200.2-0.807 440.3-0.807h436.5l7.4 2.422c18 6.055 31.7 19.477 37.8 37.137l2.7 7.871v581.27l-2.2 7.064c-6 19.477-21.2 34.21-41.1 39.76-7.5 2.119-8.5 2.119-238.3 2.119-126.9 0-230.8-0.202-230.8-0.505 0-0.202-1.1-4.44-2.5-9.183-3.5-12.009-4-16.853-3.9-33.201 0.1-15.541 2.2-27.247 7-39.559 3.2-8.174 10.2-20.385 14.8-26.036l3.4-4.037 173.3-0.202c95.4 0 173.9-0.202 174.4-0.202 0.6-0.101-2.1-2.119-6-4.541-3.8-2.422-7.5-4.945-8.2-5.55s-1.5-1.11-1.8-1.11c-1 0-17-10.495-17.3-11.302-0.2-0.505-0.8-0.807-1.3-0.807s-13.6-8.073-29.2-17.963c-15.5-9.89-46-29.265-67.7-43.091-40.3-25.531-55.7-35.32-69-43.898-4.1-2.624-16.5-10.495-27.5-17.458s-20.5-13.119-21.2-13.724c-0.7-0.605-1.4-1.11-1.7-1.11-0.8 0-17.1-10.596-17.4-11.302-0.2-0.505-0.8-0.807-1.3-0.807-1.1 0-17.2-10.192-18.1-11.605-0.4-0.505-0.8-0.605-0.8-0.101s-0.8 0.202-1.7-0.605c-2.8-2.422-48.3-31.082-49.4-31.082-0.5 0-3.3 1.514-6.2 3.431-2.8 1.917-36.5 23.311-74.7 47.531s-72.9 46.32-77 48.944c-6.4 4.138-71.5 45.513-127.5 81.035-21.2 13.422-33.3 21.091-43.3 27.651-4.5 2.927-8.7 5.348-9.2 5.348-0.6 0-1 0.605-1 1.312 0 0.908 11.1 1.211 52.2 1.11 28.8-0.101 52.6 0.101 52.9 0.202 0.4 0.202-3.4 4.339-8.3 9.183-21.5 21.192-32.6 42.082-41.3 77.503-1.5 6.156-2.9 12.009-3.1 13.119s-0.9 4.44-1.5 7.367l-1 5.248h-73.3c-40.3 0-73.5-0.202-73.7-0.505zM192.1 369.572c23.9-15.036 87.1-54.898 140.4-88.603 53.4-33.706 108.6-68.622 122.9-77.604 14.2-8.981 27.5-17.156 29.6-18.266 10.8-5.55 29.9-7.569 41.2-4.44 2.9 0.807 5.8 1.615 6.3 1.816 4.6 1.11 21.4 11.202 65 39.155 2.2 1.413 4.4 2.523 4.9 2.624 0.5 0 1.2 0.404 1.5 0.908 0.6 0.908 31.4 20.486 33.5 21.394 0.6 0.202 1.5 0.807 2.1 1.312 2.2 1.917 13.6 8.881 14.5 8.881 0.4 0 1 0.303 1.2 0.807 0.2 0.404 11.1 7.468 24.3 15.743s27 17.055 30.7 19.477c3.7 2.422 7.1 4.339 7.7 4.339 0.5 0 1.1 0.303 1.3 0.807 0.2 0.404 17.2 11.403 37.8 24.32 20.6 13.018 38.3 24.32 39.3 25.128 0.9 0.807 1.7 1.11 1.7 0.605s0.4-0.404 0.8 0.202c0.7 1.009 32.9 21.596 33.8 21.596 0.3 0 1 0.505 1.7 1.009 2.3 2.018 13.8 9.082 14.7 9.082 0.4 0 1 0.303 1.2 0.807 0.3 0.605 22.8 15.238 25 16.146 0.5 0.202 0.7-69.53 0.6-154.904l-0.3-155.207-2.4-4.541c-2.4-4.743-7.8-10.394-12.1-12.614-7.5-3.936 0.2-3.835-350-3.835l-338.5 0.101-5.7 2.119c-6.6 2.523-13.4 8.679-16.3 14.734-2 3.936-2 6.963-2.3 159.244-0.1 85.273-0.1 155.106 0.2 155.106 0.2 0 19.9-12.312 43.7-27.449z" />
-<glyph unicode="&#xe652;" glyph-name="nok" d="M1014.662 137.34c-0.004 0.004-0.008 0.008-0.012 0.010l-310.644 310.65 310.644 310.65c0.004 0.004 0.008 0.006 0.012 0.010 3.344 3.346 5.762 7.254 7.312 11.416 4.246 11.376 1.824 24.682-7.324 33.83l-146.746 146.746c-9.148 9.146-22.45 11.566-33.828 7.32-4.16-1.55-8.070-3.968-11.418-7.31 0-0.004-0.004-0.006-0.008-0.010l-310.648-310.652-310.648 310.65c-0.004 0.004-0.006 0.006-0.010 0.010-3.346 3.342-7.254 5.76-11.414 7.31-11.38 4.248-24.682 1.826-33.83-7.32l-146.748-146.748c-9.148-9.148-11.568-22.452-7.322-33.828 1.552-4.16 3.97-8.072 7.312-11.416 0.004-0.002 0.006-0.006 0.010-0.010l310.65-310.648-310.65-310.652c-0.002-0.004-0.006-0.006-0.008-0.010-3.342-3.346-5.76-7.254-7.314-11.414-4.248-11.376-1.826-24.682 7.322-33.83l146.748-146.746c9.15-9.148 22.452-11.568 33.83-7.322 4.16 1.552 8.070 3.97 11.416 7.312 0.002 0.004 0.006 0.006 0.010 0.010l310.648 310.65 310.648-310.65c0.004-0.002 0.008-0.006 0.012-0.008 3.348-3.344 7.254-5.762 11.414-7.314 11.378-4.246 24.684-1.826 33.828 7.322l146.746 146.748c9.148 9.148 11.57 22.454 7.324 33.83-1.552 4.16-3.97 8.068-7.314 11.414z" />
-<glyph unicode="&#xe653;" glyph-name="active" d="M563.090 266.543v58.034c77.516 43.683 140.741 152.585 140.741 261.505 0 174.89 0 316.666-211.111 316.666s-211.111-141.776-211.111-316.666c0-108.92 63.225-217.822 140.741-261.505v-58.034c-238.711-19.514-422.222-136.805-422.222-278.609h623.613c0 70.902-1.153 157.045-1.232 265.384-15.509 7.682-47.509 12.682-59.419 13.225zM715.841 261.148v86.759h68.505l0.001 42c0 18.887 15.365 34.252 34.252 34.252h68.506c18.887 0 34.252-15.365 34.252-34.252v-128.759h-137.012zM715.84 261.148h-8.564c-14.129 0-25.69-11.561-25.69-25.69v-256.899c0-14.129 11.561-25.69 25.69-25.69h291.151c14.129 0 25.69 11.561 25.69 25.69v256.899c0 14.129-11.561 25.69-25.69 25.69h-8.564v128.759c0 56.661-46.096 102.759-102.759 102.759h-68.506c-56.661 0-102.759-46.096-102.759-102.759zM784.345 261.148v128.759z" />
-<glyph unicode="&#xe654;" glyph-name="desactive" d="M563.090 266.543v58.034c77.516 43.683 140.741 152.585 140.741 261.505 0 174.89 0 316.666-211.111 316.666s-211.111-141.776-211.111-316.666c0-108.92 63.225-217.822 140.741-261.505v-58.034c-238.711-19.514-422.222-136.805-422.222-278.609h623.613c0 70.902-1.153 157.045-1.232 265.384-15.509 7.682-47.509 12.682-59.419 13.225zM998.428 261.148h-8.564v102.759c0 56.661-46.096 102.759-102.759 102.759h-68.506c-56.661 0-102.759-46.096-102.759-102.759v-102.759h-8.564c-14.129 0-25.69-11.561-25.69-25.69v-256.899c0-14.129 11.561-25.69 25.69-25.69h291.151c14.129 0 25.69 11.561 25.69 25.69v256.899c0 14.129-11.561 25.69-25.69 25.69zM784.347 363.906c0 18.887 15.365 34.252 34.252 34.252h68.506c18.887 0 34.252-15.365 34.252-34.252v-102.759h-137.012v102.759z" />
-<glyph unicode="&#xe655;" glyph-name="supprutilisateur" d="M563.090 266.543v58.034c77.516 43.683 140.741 152.585 140.741 261.505 0 174.89 0 316.666-211.111 316.666s-211.111-141.776-211.111-316.666c0-108.92 63.225-217.822 140.741-261.505v-58.034c-238.711-19.514-422.222-136.805-422.222-278.609l583.949-4.219c-63.823 57.711-106.553 179.321-33.459 267.293 2.844 3.934 7.477 10.066 12.472 15.535zM811.275 357.437c-115.493 0-209.119-93.626-209.119-209.119s93.626-209.119 209.119-209.119c115.492 0 209.119 93.626 209.119 209.119s-93.626 209.119-209.119 209.119zM946.612 103.93h-268.681v88.776h268.681z" />
-<glyph unicode="&#xe656;" glyph-name="valideutilisateur" d="M563.090 266.543v58.034c77.516 43.683 140.741 152.585 140.741 261.505 0 174.89 0 316.666-211.111 316.666s-211.111-141.776-211.111-316.666c0-108.92 63.225-217.822 140.741-261.505v-58.034c-238.711-19.514-422.222-136.805-422.222-278.609l595.956 0.384c-36.514 39.594-55.251 59.727-94.968 98.653 49.259 51.199 106.855 110.76 143.402 154.746-22.556 14.982-61.726 25.122-81.428 24.827zM955.207 268.179l-197.727-197.727-92.273 92.273-65.909-65.909 158.182-158.182 263.637 263.637z" />
-<glyph unicode="&#xe657;" glyph-name="lecture" d="M864 960h-768c-52.8 0-96-43.2-96-96v-832c0-52.8 43.2-96 96-96h768c52.8 0 96 43.2 96 96v832c0 52.8-43.2 96-96 96zM832 64h-704v768h704zM256 624h448v-64h-448zM256 496h448v-64h-448zM256 368h448v-64h-448zM256 752h448v-64h-448zM252.773 235.747h264v-64h-264z" />
-<glyph unicode="&#xe658;" glyph-name="nolecture" d="M222.654-64h641.346c52.8 0 96 43.2 96 96v665.218l-128-141.521v-491.697h-483.654zM128 285.494v546.506h563.031l120.969 128h-716c-52.8 0-96-43.2-96-96v-711.425zM256 624h448v-64h-448zM256 496h448v-64h-448zM256 368h448v-64h-448zM256 752h448v-64h-448zM252.773 239.747h264v-64h-264zM993.909 929.806c-19.541 19.659-51.221 19.659-70.762 0l-900.658-906.169c-19.541-19.661-19.541-51.534 0-71.195 9.77-9.832 22.575-14.746 35.38-14.746s25.61 4.915 35.382 14.744l900.658 906.169c19.539 19.661 19.539 51.536 0 71.197z" />
-</font></defs></svg>
\ No newline at end of file
Binary files cahier-de-prepa8.1.1/fonts/icomoon.ttf and cahier-de-prepa9.0.0/fonts/icomoon.ttf differ
Binary files cahier-de-prepa8.1.1/fonts/icomoon.woff and cahier-de-prepa9.0.0/fonts/icomoon.woff differ
diff -urN cahier-de-prepa8.1.1/gestioncompte.php cahier-de-prepa9.0.0/gestioncompte.php
--- cahier-de-prepa8.1.1/gestioncompte.php	2018-11-08 00:16:10.612404999 +0100
+++ cahier-de-prepa9.0.0/gestioncompte.php	2019-08-27 00:06:35.887802962 +0200
@@ -25,7 +25,7 @@
   // oublimdp&mail (ajax) -> envoi du mail de vérification
   // oublimdp&mail&p (retour mail, get) -> affichage du formulaire des mdp
   // oublimdp&mail&p&mdp1&mdp2 (ajax) -> ok
-  // p est le sha1 de $site.$mdp.date('Y-m-d-H').$mail
+  // p est le sha1 de $chemin.$mdp.date('Y-m-d-H').$mail
   $action = 'oublimdp';
 elseif ( isset($_REQUEST['creation']) ) {
   // 4 étapes :
@@ -34,7 +34,7 @@
   // creation&mail&p (retour mail, get) -> affichage du formulaire des mdp
   // creation&mail&p&prenom&nom&mdp1&mdp2&autorisation (ajax) -> ok
   // $creation_compte réglée dans config.php : true si création autorisée
-  // p est le sha1 de $site.$mdp.date('Y-m-d-H').$mail
+  // p est le sha1 de $chemin.$mdp.date('Y-m-d-H').$mail
   $action = 'creation';
   // Vérification de l'ouverture des créations de compte
   $mysqli = connectsql();
@@ -53,7 +53,7 @@
   // 2 étapes :
   // invitation&mail&p (retour mail généré dans ajax.php) -> formulaire
   // invitation&mail&p&mdp1&mdp2 (ajax) -> ok
-  // p est le sha1 de $site.$mdp.$mail (validité permanente)
+  // p est le sha1 de $chemin.$mdp.$mail (validité permanente)
   $action = 'invitation';
 else  {
   // Aucune action
@@ -82,9 +82,10 @@
   }
   if ( isset($_REQUEST['p']) )  {
     $p = $_REQUEST['p'];
-    // Pour invitation, $p est le hash de $site.$mdp.$mail
-    // Pour oublimdp et creation, $site.$mdp.date('Y-m-d-H').$mail
-    if ( !( ( $action == 'invitation' ) && ( $p == sha1($site.$mdp.$mail) ) || ( $p == sha1($site.$mdp.date('Y-m-d-H').$mail) ) || ( $p == sha1($site.$mdp.date('Y-m-d-H',time()+900).$mail) ) ) )  {
+    // Pour invitation, $p est le sha1 de $chemin.$mdp.$mail 
+    // (précédemment avec $domaine.$chemin sans le slash, condition transitoire)
+    // Pour oublimdp et creation, $chemin.$mdp.date('Y-m-d-H').$mail
+    if ( !( ( $action == 'invitation' ) && ( ( $p == sha1($chemin.$mdp.$mail) ) || ( $p == sha1($domaine.substr($chemin,0,-1).$mdp.$mail) ) ) || ( $p == sha1($chemin.$mdp.date('Y-m-d-H').$mail) ) || ( $p == sha1($chemin.$mdp.date('Y-m-d-H',time()+900).$mail) ) ) )  {
       if ( $_SERVER['REQUEST_METHOD'] == 'GET' )  {
         $mysqli = connectsql();
         debut($mysqli,$titre,'',false);
@@ -122,11 +123,11 @@
         // On ajoute 15 minutes au temps utilisé : de xh00 à xh45,
         // on a jusqu'à (x+1)h, de xh45 à (x+1)h on a jusqu'à (x+2)h
         $t = time() + 900;
-        $lien = 'https://'.$site.'/gestioncompte?oublimdp&mail='.str_replace('@','__',$mail).'&p='.sha1($site.$mdp.date('Y-m-d-H',$t).$mail);
+        $lien = "https://$domaine${chemin}gestioncompte?oublimdp&mail=".str_replace('@','__',$mail).'&p='.sha1($chemin.$mdp.date('Y-m-d-H',$t).$mail);
         mail($mail,'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Changement de mot de passe').'?=',
 "Bonjour
 
-Vous avez rempli une demande de modification de votre mot de passe sur le Cahier de Prépa <https://$site>, correspondant à l'identifiant ${utilisateur['login']}.
+Vous avez rempli une demande de modification de votre mot de passe sur le Cahier de Prépa <https://$domaine$chemin>, correspondant à l'identifiant ${utilisateur['login']}.
 
 Si cette demande ne vient pas de vous ou si vous avez retrouvé votre mot de passe, merci d'ignorer simplement ce courriel.
 
@@ -151,8 +152,14 @@
           $permconn .= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[random_int(0,61)];
         // Écriture du nouveau mot de passe
         $mysqli = connectsql(true);
-        if( requete('utilisateurs',"UPDATE utilisateurs SET mdp = '".sha1($mdp.$newmdp)."', permconn = IF(permconn > '','$permconn','') WHERE id = ${utilisateur['id']}",$mysqli) )
+        if( requete('utilisateurs',"UPDATE utilisateurs SET mdp = '".sha1($mdp.$newmdp)."', permconn = IF(permconn > '','$permconn','') WHERE id = ${utilisateur['id']}",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( $interfaceglobale )  {
+            include("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($utilisateur['id'],array('mdp'=>sha1($mdp.$newmdp)));
+          }
           exit('{"etat":"ok_","message":"Votre mot de passe a bien été modifié.</p><p class=\"warning\"><a href=\".\">Retourner au Cahier de Prépa</a></p>"}');
+        }
         exit('{"etat":"nok_","message":"Votre mot de passe n\'a pas pu être modifié suite à une erreur technique."}' );
       }
       break;
@@ -161,8 +168,8 @@
     case 'creation': {
 
       // Impossibilités classiques
-      if ( in_array($domaine = strstr($mail,'@'),array('@gmail.fr','@laposte.fr')) )
-        exit('{"etat":"nok_","message":"L\'adresse saisie ne pourra pas fonctionner&nbsp;: le domaine <code>'.$domaine.'</code> ne reçoit pas de courriels."}');
+      if ( in_array($dom = strstr($mail,'@'),array('@gmail.fr','@laposte.fr')) )
+        exit('{"etat":"nok_","message":"L\'adresse saisie ne pourra pas fonctionner&nbsp;: le domaine <code>'.$dom.'</code> ne reçoit pas de courriels."}');
       // Recherche du mail dans la base de données
       $mysqli = connectsql();
       $resultat = $mysqli->query('SELECT id, login, mail FROM utilisateurs');
@@ -179,11 +186,11 @@
         // On ajoute 15 minutes au temps utilisé : de xh00 à xh45,
         // on a jusqu'à (x+1)h, de xh45 à (x+1)h on a jusqu'à (x+2)h
         $t = time() + 900;
-        $lien = 'https://'.$site.'/gestioncompte?creation&mail='.str_replace('@','__',$mail).'&p='.sha1($site.$mdp.date('Y-m-d-H',$t).$mail);
+        $lien = "https://$domaine${chemin}gestioncompte?creation&mail=".str_replace('@','__',$mail).'&p='.sha1($chemin.$mdp.date('Y-m-d-H',$t).$mail);
         mail($mail,'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Création de compte').'?=',
 "Bonjour
 
-Vous venez de donner cette adresse pour une demande de création de compte sur le Cahier de Prépa <https://$site>.
+Vous venez de donner cette adresse pour une demande de création de compte sur le Cahier de Prépa <https://$domaine$chemin>.
 
 Si cette demande ne vient pas de vous, merci d'ignorer simplement ce courriel.
 
@@ -226,8 +233,14 @@
           exit('{"etat":"nok_","message":"Un compte avec le même identifiant existe déjà. Merci de vous connecter avec l\'adresse électronique correspondante."}');
         // Écriture du nouveau compte
         $mysqli = connectsql(true);
-        if( requete('utilisateurs',"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '$mail', mdp = '*$newmdp', autorisation = 2, matieres = CONCAT('0,',(SELECT GROUP_CONCAT(id) AS matieres FROM matieres)), timeout = 3600, mailexp = '$prenom $nom', mailcopie = 1, mailenvoi = 0, permconn = ''",$mysqli) )
+        if( requete('utilisateurs',"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '$mail', mdp = '*$newmdp', autorisation = 2, matieres = CONCAT('0,',(SELECT GROUP_CONCAT(id) AS matieres FROM matieres)), timeout = 3600, mailexp = '$prenom $nom', mailcopie = 1, mailenvoi = 0, permconn = ''",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( $interfaceglobale )  {
+            include("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($mysqli->insert_id,"INSERT INTO utilisateurs SET login = '$login', prenom = '$prenom', nom = '$nom', mail = '$mail', mdp = '*$newmdp', autorisation = 2");
+          }
           exit('{"etat":"ok_","message":"Votre demande d\'inscription est terminée. Elle est maintenant en attente de validation par les professeurs de la classe. Vous recevrez un courriel lorsque votre inscription sera validée.</p><p class=\"warning\"><a href=\".\">Retourner au Cahier de Prépa</a></p>"}');
+        }
         exit('{"etat":"nok_","message":"Votre demande d\'inscription n\'a pas pu être enregistrée suite à une erreur technique."}');
       }
       break;
@@ -257,14 +270,16 @@
       if ( isset($_REQUEST['mdp1']) && strlen($newmdp = $_REQUEST['mdp1']) )  {
         if ( $newmdp != $_REQUEST['mdp2'] )
           exit('{"etat":"nok_","message":"Les deux mots de passe donnés ne sont pas identiques."}');
-        // Token de connexion automatique
-        $permconn = '';
-        for ( $i = 0; $i < 10; $i++ )
-          $permconn .= '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'[random_int(0,61)];
         // Écriture du nouveau mot de passe
         $mysqli = connectsql(true);
-        if( requete('utilisateurs',"UPDATE utilisateurs SET mdp = '".sha1($mdp.$newmdp)."', permconn = '$permconn' WHERE id = ${utilisateur['id']}",$mysqli) )
+        if( requete('utilisateurs',"UPDATE utilisateurs SET mdp = '".sha1($mdp.$newmdp)."' WHERE id = ${utilisateur['id']}",$mysqli) )  {
+          // Si interface globale activée, mise à jour
+          if ( $interfaceglobale )  {
+            include("${interfaceglobale}majutilisateurs.php");
+            majutilisateurs($utilisateur['id'],array('mdp'=>sha1($mdp.$newmdp)));
+          }
           exit('{"etat":"ok_","message":"Votre mot de passe a bien été modifié. Votre compte est opérationnel.</p><p class=\"warning\"><a href=\".\">Retourner au Cahier de Prépa</a></p>"}');
+        }
         exit('{"etat":"nok_","message":"Votre mot de passe n\'a pas pu être modifié suite à une erreur technique."}');
       }
     }
diff -urN cahier-de-prepa8.1.1/groupes.php cahier-de-prepa9.0.0/groupes.php
--- cahier-de-prepa8.1.1/groupes.php	2018-10-13 00:14:13.766307094 +0200
+++ cahier-de-prepa9.0.0/groupes.php	2019-08-28 10:39:21.712149670 +0200
@@ -12,7 +12,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
@@ -38,13 +38,13 @@
     switch ( $a )  {
       case 2 : $t = 'Élèves'; break;
       case 3 : $t = 'Colleurs'; break;
-      case 4 : $t = 'Administratifs'; break;
+      case 4 : $t = 'Lycée'; break;
       case 5 : $t = 'Professeurs'; break;
     }
     $table .= <<<FIN
         <tr class="categorie">
           <th>$t</th>
-          <th><a class="icon-cocher"></a></th>
+          <th class="icone"><a class="icon-cocher"></a></th>
         </tr>
 
 FIN;
@@ -53,7 +53,7 @@
   elseif ( $r['desactive'] == 1 )   $r['nomcomplet'] .= ' (compte désactivé)';
   elseif ( $r['demande'] == 1 )     $r['nomcomplet'] .= ' (demande non répondue)';
   elseif ( $r['invitation'] == 1 )  $r['nomcomplet'] .= ' (invitation non répondue)';
-  $table .= "        <tr><td>${r['nomcomplet']}</td><td><input type=\"checkbox\" id=\"u${r['id']}\"></td></tr>\n";
+  $table .= "        <tr><td>${r['nomcomplet']}</td><td class=\"icone\"><input type=\"checkbox\" id=\"u${r['id']}\"></td></tr>\n";
 }
 $resultat->free();
 
@@ -101,7 +101,7 @@
     <a class="icon-ok" title="Valider ces utilisateurs"></a>
     <h3>Choix des utilisateurs du groupe </h3>
     <form>
-    <table>
+    <table class="utilisateurs">
       <tbody>
 <?php echo $table; ?>
       </tbody>
@@ -127,8 +127,9 @@
       <li>l'envoi de courriels&nbsp;: ils sont listés à la suite des expéditeurs possibles, pour les sélectionner plus facilement. Ils peuvent regrouper des utilisateurs de tout type.</li>
       <li>la saisie de notes de colles&nbsp;: ils permettent une sélection rapide des élèves à noter. Ils sont logiquement censés regrouper des élèves uniquement.</li>
     </ul>
-    <p>Les groupes pour l'envoi de courriel ne sont en réalité affichés que pour les utilisateurs colleur/administration/professeur. Les élèves qui peuvent éventuellement envoyer des courriels ne voient pas les groupes. Il est donc possible de faire des groupes «&nbsp;Colleurs de XXX&nbsp;» ou «&nbsp;Équipe pédagogique&nbsp;» par exemple.</p>
+    <p>Les groupes pour l'envoi de courriel ne sont en réalité affichés que pour les utilisateurs colleur/lycée/professeur. Si les élèves peuvent envoyer des courriels (réglage sur la page de <a href="utilisateurs-mails">gestion des courriels</a>), ils ne voient pas les groupes. Il est donc possible de faire des groupes «&nbsp;Colleurs de [matière]&nbsp;» ou «&nbsp;Équipe pédagogique&nbsp;» par exemple.</p>
     <p>Les groupes d'utilisateurs ne se limitent pas aux groupes de colles, il peut être notamment intéressant de créer les deux demi-groupes de la classe ou les groupes d'option par exemple, pour envoyer des courriels aux seuls élèves concernés le cas échéant.</p>
+    <p>Les notes de colles peuvent être mises à cheval sur plusieurs groupes. Ce n'est pas grave si parfois un élève ne colle pas avec le reste de son groupe marqué ici.</p>
     <p>Chaque utilisateur peut participer à plusieurs groupes. Chaque groupe peut contenir jusqu'à l'ensemble des utilisateurs, sans limite de type de compte ou de matière associée.</p>
     <p>Un clic sur l'icône <span class="icon-ajoute"></span> permet d'ouvrir le formulaire permettant de créer un nouveau groupe.</p>
     <h4>Modification des groupes</h4>
@@ -147,8 +148,9 @@
       <li>l'envoi de courriels&nbsp;: ils sont listés à la suite des expéditeurs possibles, pour les sélectionner plus facilement. Ils peuvent regrouper des utilisateurs de tout type.</li>
       <li>la saisie de notes de colles&nbsp;: ils permettent une sélection rapide des élèves à noter. Ils sont logiquement censés regrouper des élèves uniquement.</li>
     </ul>
-    <p>Les groupes pour l'envoi de courriel ne sont en réalité affichés que pour les utilisateurs colleur/administration/professeur. Les élèves qui peuvent éventuellement envoyer des courriels ne voient pas les groupes. Il est donc possible de faire des groupes «&nbsp;Colleurs de XXX&nbsp;» ou «&nbsp;Équipe pédagogique&nbsp;» par exemple.</p>
+    <p>Les groupes pour l'envoi de courriel ne sont en réalité affichés que pour les utilisateurs colleur/lycée/professeur. Si les élèves peuvent envoyer des courriels (réglage sur la page de <a href="utilisateurs-mails">gestion des courriels</a>), ils ne voient pas les groupes. Il est donc possible de faire des groupes «&nbsp;Colleurs de [matière]&nbsp;» ou «&nbsp;Équipe pédagogique&nbsp;» par exemple.</p>
     <p>Les groupes d'utilisateurs ne se limitent pas aux groupes de colles, il peut être notamment intéressant de créer les deux demi-groupes de la classe ou les groupes d'option par exemple, pour envoyer des courriels aux seuls élèves concernés le cas échéant.</p>
+    <p>Les notes de colles peuvent être mises à cheval sur plusieurs groupes. Ce n'est pas grave si parfois un élève ne colle pas avec le reste de son groupe marqué ici.</p>
     <p>Les groupes sont automatiquement classés par ordre alphanumérique.</p>
     <h4>Préférence du groupe</h4>
     <p>Le <em>nom du groupe</em> est ce qui apparaîtra derrière la mention &laquo;&nbsp;Groupe&nbsp;&raquo;. Il peut s'agir d'un simple numéro (1,2,3...) pour des groupes de colles, d'une lettre ou d'un mot pour des demi-groupes par exemple (A et B, impairs et pairs...), ou encore d'un nom plus long (&laquo;&nbsp;Colleurs de Mathématiques&nbsp;&raquo;...).</p>
@@ -168,8 +170,9 @@
       <li>l'envoi de courriels&nbsp;: ils sont listés à la suite des expéditeurs possibles, pour les sélectionner plus facilement. Ils peuvent regrouper des utilisateurs de tout type.</li>
       <li>la saisie de notes de colles&nbsp;: ils permettent une sélection rapide des élèves à noter. Ils sont logiquement censés regrouper des élèves uniquement.</li>
     </ul>
-    <p>Les groupes pour l'envoi de courriel ne sont en réalité affichés que pour les utilisateurs colleur/administration/professeur. Les élèves qui peuvent éventuellement envoyer des courriels ne voient pas les groupes. Il est donc possible de faire des groupes «&nbsp;Colleurs de XXX&nbsp;» ou «&nbsp;Équipe pédagogique&nbsp;» par exemple.</p>
+    <p>Les groupes pour l'envoi de courriel ne sont en réalité affichés que pour les utilisateurs colleur/lycée/professeur. Si les élèves peuvent envoyer des courriels (réglage sur la page de <a href="utilisateurs-mails">gestion des courriels</a>), ils ne voient pas les groupes. Il est donc possible de faire des groupes «&nbsp;Colleurs de [matière]&nbsp;» ou «&nbsp;Équipe pédagogique&nbsp;» par exemple.</p>
     <p>Les groupes d'utilisateurs ne se limitent pas aux groupes de colles, il peut être notamment intéressant de créer les deux demi-groupes de la classe ou les groupes d'option par exemple, pour envoyer des courriels aux seuls élèves concernés le cas échéant.</p>
+    <p>Les notes de colles peuvent être mises à cheval sur plusieurs groupes. Ce n'est pas grave si parfois un élève ne colle pas avec le reste de son groupe marqué ici.</p>
     <p>Les cases à cocher pour définir l'utilisation des groupes sur les courriels ou les notes agissent immédiatement&nbsp;: cocher ou décocher active ou désactive l'utilisation, sans validation supplémentaire.</p>
     <h4>Ordre des groupes</h4>
     <p>Les groupes sont automatiquement classés par ordre alphanumérique.</p>
diff -urN cahier-de-prepa8.1.1/index.php cahier-de-prepa9.0.0/index.php
--- cahier-de-prepa8.1.1/index.php	2018-10-17 09:14:01.897443151 +0200
+++ cahier-de-prepa9.0.0/index.php	2019-08-26 01:35:59.880410418 +0200
@@ -66,7 +66,7 @@
     $resultat = $mysqli->query('SELECT m.nom AS matiere, t.nom AS type, texte,
                               DATE_FORMAT(debut,\'%w%Y%m%e\') AS d, DATE_FORMAT(fin,\'%w%Y%m%e\') AS f,
                               DATE_FORMAT(debut,\'%kh%i\') AS hd, DATE_FORMAT(fin,\'%kh%i\') AS hf
-                              FROM agenda AS a JOIN `agenda-types` AS t ON a.type = t.id LEFT JOIN matieres AS m ON a.matiere = m.id
+                              FROM agenda AS a LEFT JOIN `agenda-types` AS t ON a.type = t.id LEFT JOIN matieres AS m ON a.matiere = m.id
                               WHERE CURDATE() <= DATE(fin) AND ADDDATE(CURDATE(),7) >= DATE(debut) ORDER BY debut,fin LIMIT '.$n);
     if ( $resultat->num_rows )  {
       echo "\n  <h2><a href=\"agenda\" title=\"Afficher l'agenda du mois\" style=\"text-decoration: none;\"><span class=\"icon-agenda\"></span></a>&nbsp;Prochains événements</h2>\n\n  <article>";
@@ -150,7 +150,7 @@
           $lock = '<span class="icon-locktotal" title="Information invisible"></span>';
         }
         else  {
-          $texte = array('invités','élèves','colleurs','administratifs','professeurs');
+          $texte = array('invités','élèves','colleurs','lycée','professeurs');
         for ( $a=0; $a<5; $a++ )
           if ( ( ($p-1)>>$a & 1 ) == 1 )
             unset($texte[$a]);
@@ -183,7 +183,7 @@
     <a class="icon-monte"$monte title="Déplacer cette information vers le haut"></a>
     <a class="icon-descend"$descend title="Déplacer cette information vers le bas"></a>
     <a class="icon-supprime" title="Supprimer cette information"></a>
-    <div class="editable edithtml" data-id="infos|texte|${r['id']}" placeholder="Texte de l'information (obligatoire)">
+    <div class="editable edithtml majpubli" data-id="infos|texte|${r['id']}" placeholder="Texte de l'information (obligatoire)">
 ${r['texte']}
     </div>$texte
   </article>
@@ -202,7 +202,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Administratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Information invisible</option>';
   // Protection des nouvelles informations = protection globale de la page
@@ -241,7 +241,7 @@
       <select name="protection[]" multiple><?php echo str_replace('Information','Page',$sel_protection); ?>
       </select>
     </p>
-    <p class="ligne"><label for="propagation">Propager l'accès à chaque information de la page&nbsp;: </label><input type="checkbox" id="propagation" name="propagation" value="1"></p>
+    <p class="ligne"><label for="propagation">Propager ce choix d'accès à chaque information de la page&nbsp;: </label><input type="checkbox" id="propagation" name="propagation" value="1"></p>
     <p class="ligne"><label for="bandeau">Texte de début&nbsp;:</label></p>
     <textarea name="bandeau" rows="2" cols="100" placeholder="Texte apparaissant au début de la page (non obligatoire)"><?php echo $page['bandeau']; ?></textarea>
     <input type="hidden" name="id" value="<?php echo $page['id']; ?>">
diff -urN cahier-de-prepa8.1.1/installation.php cahier-de-prepa9.0.0/installation.php
--- cahier-de-prepa8.1.1/installation.php	2018-10-31 11:27:21.732088029 +0100
+++ cahier-de-prepa9.0.0/installation.php	2019-08-29 00:19:53.292365207 +0200
@@ -35,10 +35,10 @@
 
 // Recharge de la page si elle est lancée par un autre script (donc config.php déjà appelé)
 if ( defined('OK') )  {
-  // Si $site est vide : config.php n'a pas été modifié correctement
-  if ( !strlen($site) )
+  // Si $chemin est vide : config.php n'a pas été modifié correctement
+  if ( !$domaine )
     exit($header.'<h3 class="warning">Le fichier de configuration n\'existe pas, n\'est pas lisible ou est mal rempli.</h3><article><p>Il doit s\'appeler <code>config.php</code>, se trouver au même endroit que l\'ensemble des fichiers constituant le site et être lisible par l\'utilisateur d\'Apache (<code>'.`whoami | tr -d '\n'`.'</code>).</p><p>Vous devez l\'éditer pour y mettre les bonnes valeurs.</p></article>'.$footer);
-  header("Location: https://$site/installation");
+  header("Location: https://$domaine${chemin}installation");
   exit();
 }
 
@@ -50,7 +50,7 @@
 else
   exit($header.'<h3 class="warning">Le fichier de configuration n\'existe pas ou n\'est pas lisible.</h3><article><p>Il doit s\'appeler config.php, se trouver au même endroit que l\'ensemble des fichiers constituant le site et être lisible par l\'utilisateur d\'Apache (<code>'.`whoami | tr -d '\n'`.'</code>).</p></article>'.$footer);
 // Vérification des données du fichier de configuration
-if ( !isset($site) || !isset($serveur) || !isset($base) || !isset($mdp) )
+if ( !isset($domaine) || !isset($chemin) || !isset($serveur) || !isset($base) || !isset($mdp) )
   exit($header.'<h3 class="warning">Le fichier de configuration est incomplet.</h3><article><p>Il manque des données nécessaire au fonctionnement du site dans le fichier <code>config.php</code>. Il faut l\'éditer et le modifier manuellement.</p></article>'.$footer);
 if ( strlen($base) > 12 )
   exit($header.'<h3 class="warning">Le nom de la base de données est trop long.</h3><article><p>Le nom de la base de données ne doit pas être supérieur à 12 caractères. Il faut corriger manuellement cela dans le fichier de configuration  <code>config.php</code>.</p></article>'.$footer);
@@ -58,23 +58,23 @@
 ///////////////////////////////
 // Connexion obligatoire à partir d'ici, en entrant le mot de passe du fichier de configuration
 ///////////////////////////////
-session_name(md5("$site-install"));
-session_set_cookie_params(0,strchr($site,'/').'/',str_replace(strchr($site,'/'),'',$site));
+session_name('CDP_SESSION_INSTALLATION');
+session_set_cookie_params(0,$chemin,$domaine,true);
 session_start();
 if ( isset($_REQUEST['motdepasse']) && ( $_REQUEST['motdepasse'] == $mdp ) )  {
   // Interdiction de garder son identifiant de session
   session_regenerate_id(true);
   $_SESSION = array();
   // Pour vérification aux connexions ultérieures
-  $_SESSION[md5("$site")] = true;
+  $_SESSION['cahier'] = "$domaine$chemin";
   $_SESSION['client'] = $_SERVER['HTTP_USER_AGENT'];
   $_SESSION['ip'] = $_SERVER['REMOTE_ADDR'];
   $_SESSION['time'] = time()+600;
 }
-elseif ( !isset($_SESSION[md5("$site")]) || ( $_SESSION['time'] < time() ) || isset($_REQUEST['deconnexion']) || ( $_SESSION['client'] != $_SERVER['HTTP_USER_AGENT'] ) || ( $_SESSION['ip'] != $_SERVER['REMOTE_ADDR'] ) )  {
+elseif ( !isset($_SESSION['cahier']) || ( $_SESSION['cahier'] != "$domaine$chemin" ) || ( $_SESSION['time'] < time() ) || isset($_REQUEST['deconnexion']) || ( $_SESSION['client'] != $_SERVER['HTTP_USER_AGENT'] ) || ( $_SESSION['ip'] != $_SERVER['REMOTE_ADDR'] ) )  {
   // Suppression du cookie et des données de session
   $_SESSION = array();
-  setcookie(session_name(),'',time()-3600);
+  setcookie(session_name(),'',time()-3600,$chemin,$domaine,true);
   session_regenerate_id(true);
   echo <<<FIN
 $header
@@ -163,11 +163,11 @@
           // Envoi du courriel d'invitation 
           if ( !isset($mailadmin) )
             $mailadmin = 'admin@cahier-de-prepa.fr';
-          $lien = "https://$site/gestioncompte?invitation&mail=$mail&p=".sha1($site.$mdp.$mail);
+          $lien = "https://$domaine${chemin}gestioncompte?invitation&mail=".str_replace('@','__',$mail).'&p='.sha1($chemin.$mdp.$mail);
           mail($mail,'=?UTF-8?B?'.base64_encode('[Cahier de Prépa] Invitation').'?=',
 "Bonjour
 
-Le Cahier de Prépa vient d'être créé à l'adresse <https://$site>. Vous devez avant toute chose vous rendre à la page qui vous permettra de saisir un mot de passe :
+Le Cahier de Prépa vient d'être créé à l'adresse <https://$domaine$chemin>. Vous devez avant toute chose vous rendre à la page qui vous permettra de saisir un mot de passe :
   $lien
 
 Les mots de passe sont chiffrés avant d'être stockés dans la base de données. Cela signifie que, sauf s'il est trop simple, votre mot de passe sera en complète sécurité : personne ne pourra jamais y avoir accès. Il est quand même dangereux que ce mot de passe soit évident, parce qu'un élève pourrait le deviner en vous voyant de loin le taper par exemple. Un bon mot de passe est un mot de passe d'au moins 8 caractères contenant des lettres, des chiffres et au moins un symbole parmi « ? ; : ! . , - _ ».
@@ -254,7 +254,7 @@
 }
 
 // Installation
-affiche("Ce Cahier de Prépa semble correctement installé. Page d'accueil&nbsp;: <a href=\".\">https://$site/</a>",true);
+affiche("Ce Cahier de Prépa semble correctement installé. Page d'accueil&nbsp;: <a href=\".\">https://$domaine$chemin</a>",true);
 
 // Connexion en lecture
 affiche('Connexion à la base de donnée en lecture',true);
@@ -292,28 +292,22 @@
 $resultat->free();
 
 // La base de données doit contenir 44 semaines en 2018-19
-$resultat = $mysqli->query('SELECT id FROM semaines WHERE debut > \'2018-08-01\' AND debut < \'2019-08-01\'');
+$resultat = $mysqli->query('SELECT id FROM semaines WHERE debut > \'2019-08-01\' AND debut < \'2020-08-01\'');
 affiche('Définition des semaines',$resultat->num_rows == 44);
 $resultat->free();
 $mysqli->close();
 
-// Vérification du répertoire "documents"
-if ( !is_dir('documents') )
-  affiche('Le répertoire «&nbsp;documents&nbsp;» n\'existe pas à la racine du site web.',false);
-elseif ( !is_readable('documents') || !is_executable('documents') || !is_writable('documents') )
-  affiche('Le répertoire «&nbsp;documents&nbsp;» n\'a pas les bons droits d\'accès. Il doit être accessible en lecture et en écriture. Vous pouvez taper en console&nbsp;:<br>
-  <code>cd '.dirname($_SERVER['SCRIPT_FILENAME']).' && sudo chgrp '.`id -gn | tr -d '\n'`.' documents && sudo chmod g+w documents</code>',false);
-else 
-  affiche('Répertoire «&nbsp;documents&nbsp;» accessible en lecture et écriture',1);
-
-// Vérification du répertoire "sauvegarde"
-if ( !is_dir('sauvegarde') )
-  affiche('Le répertoire «&nbsp;sauvegarde&nbsp;» n\'existe pas à la racine du site web.',false);
-elseif ( !is_readable('sauvegarde') || !is_executable('sauvegarde') || !is_writable('sauvegarde') )
-  affiche('Le répertoire «&nbsp;sauvegarde&nbsp;» n\'a pas les bons droits d\'accès. Il doit être accessible en lecture et en écriture. Vous pouvez taper en console&nbsp;:<br>
-  <code>cd '.dirname($_SERVER['SCRIPT_FILENAME']).' && sudo chgrp '.`id -gn | tr -d '\n'`.' sauvegarde && sudo chmod g+w sauvegarde</code>',false);
-else 
-  affiche('Répertoire «&nbsp;sauvegarde&nbsp;» accessible en lecture et écriture',true);
+// Vérification des répertoires
+$reps = array('documents','sauvegarde','rss');
+foreach ( $reps as $rep )  {
+  if ( !is_dir('documents') )
+    affiche('Le répertoire «&nbsp;documents&nbsp;» n\'existe pas à la racine du site web.',false);
+  elseif ( !is_readable('documents') || !is_executable('documents') || !is_writable('documents') )
+    affiche("Le répertoire «&nbsp;$rep&nbsp;» n'a pas les bons droits d'accès. Il doit être accessible en lecture et en écriture. Vous pouvez taper en console&nbsp;:<br>
+    <code>cd ".dirname($_SERVER['SCRIPT_FILENAME']).' && sudo chgrp '.`id -gn | tr -d '\n'`." $rep && sudo chmod g+w $rep</code>",false);
+  else 
+    affiche("Répertoire «&nbsp;$rep&nbsp;» accessible en lecture et écriture",1);
+}
 
 // Vérification de la quantité de données téléchargeable
 if ( '2M' == ini_get('upload_max_filesize') )
diff -urN cahier-de-prepa8.1.1/js/edition.js cahier-de-prepa9.0.0/js/edition.js
--- cahier-de-prepa8.1.1/js/edition.js	2018-11-11 00:20:29.815056064 +0100
+++ cahier-de-prepa9.0.0/js/edition.js	2019-08-26 20:32:32.083006540 +0200
@@ -48,13 +48,13 @@
   // Création de la fenêtre d'indentification
   if ( light )
     popup('<a class="icon-ok" title="Valider"></a><h3>Connexion nécessaire</h3>\
-           <p>Vous êtes déjà connecté, mais vous devez saisir de nouveau votre mot de passe pour '+action+'.</p>\
+           <p>Votre connexion est active, mais vous devez saisir de nouveau votre mot de passe pour '+action+'.</p>\
            <form>\
            <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepasse"></p>\
            </form>',true);
   else
     popup('<a class="icon-ok" title="Valider"></a><h3>Connexion nécessaire</h3>\
-           <p>Vous avez été automatiquement déconnecté. Vous devez vous connecter à nouveau pour '+action+'.</p>\
+           <p>Votre connexion a été automatiquement désactivée. Vous devez vous connecter à nouveau pour '+action+'.</p>\
            <form>\
            <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" name="login" id="login"></p>\
            <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepasse"></p>\
@@ -128,7 +128,22 @@
 
 // Fonction de pliage/dépliage vertical des lignes dans un tableau
 function plie() {
-  $(this).parent().parent().nextUntil('.categorie').fadeToggle("slow");
+  var lignes = $(this).parent().parent().nextUntil('.categorie');
+  if ( $(this).hasClass('icon-deplie') )  {
+    lignes.children().wrapInner('<div></div>').addClass('cache');
+    lignes.find('div').slideUp(1000); 
+    window.setTimeout(function() { 
+      lignes.hide().children().html(function(){ return $(this).children().html(); });
+    },1000);
+  }
+  else  {
+    lignes.show();
+    lignes.children().wrapInner('<div style="display:none;"></div>');
+    lignes.find('div').slideDown(1000);
+    window.setTimeout(function() { 
+      lignes.children().html(function(){ return $(this).children().html(); }).removeClass('cache'); 
+    },1000);
+  }
   $(this).toggleClass('icon-plie icon-deplie');
 }
 
@@ -238,8 +253,15 @@
 function transforme() {
   var el = $(this).parent().addClass('avecform');
   // Création d'une textarea si div, d'un input sinon
-  if ( el.is('div') )
-    el.html('<form><textarea name="val" rows="'+(el.data('original').split(/\r\n|\r|\n/).length+3)+'"></textarea></form>');
+  if ( el.is('div') )  {
+    // Cas des informations et colles : case à cocher pour maj de la date de publi
+    if ( el.hasClass('majpubli') )
+      el.html('<form><textarea name="val" rows="'+(el.data('original').split(/\r\n|\r|\n/).length+3)+'"></textarea><p class="ligne"><label for="publi">Publier en tant que mise à jour&nbsp;: </label><input type="checkbox" id="publi" name="publi" value="1" checked></p></form>');
+    else
+      el.html('<form><textarea name="val" rows="'+(el.data('original').split(/\r\n|\r|\n/).length+3)+'"></textarea></form>');
+    // Ne pas quitter avec un textarea plein
+    $('textarea:visible').on('change',function(e) { $('body').data('nepassortir',true); $(this).off(e); });
+  }
   else
     el.html('<form class="edition" onsubmit="$(this).children(\'a.icon-ok\').click(); return false;"><input type="text" name="val" value=""></form>');
   // Identifiant de l'input ou de la textarea
@@ -257,7 +279,7 @@
     // Envoi
     $.ajax({url: 'ajax.php',
             method: "post",
-            data: { action:id[0], champ:id[1], id:id[2], val:input.val() },
+            data: { action:id[0], champ:id[1], id:id[2], val:input.val(), publi:el.find(':checkbox').is(':checked') || undefined },
             dataType: 'json',
             el: el,
             fonction: function(el) {
@@ -301,6 +323,8 @@
     $('#'+cle).val(valeurs[cle]);
   // Mise en place des facilités  
   form.init_cdt_boutons();
+  // Ne pas quitter avec un textarea plein
+  $('textarea',form).on('change',function(e) { $('body').data('nepassortir',true); $(this).off(e); });
   // Mise à jour du titre si modification
   $('input,#demigroupe',form).on('change keyup', function() {
     var t = new Date($('#jour').val().replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z) {return z+'-'+y+'-'+x; }));
@@ -1083,7 +1107,7 @@
             dataType: 'json',
             el: parent,
             fonction: function(el) {
-              if ( prop[0].match(/^(agenda|colles)$/) )
+              if ( prop[0].match(/^(agenda-elems|colles)$/) )
                 location.reload(true);
               else
                 el.remove();
@@ -1104,7 +1128,7 @@
   <tr class="element"><td>Invités</td><td><input value="1" type="checkbox"></td></tr>\
   <tr class="element"><td>Élèves</td><td><input value="2" type="checkbox"></td></tr>\
   <tr class="element"><td>Colleurs</td><td><input value="3" type="checkbox"></td></tr>\
-  <tr class="element"><td>Administratifs</td><td><input value="4" type="checkbox"></td></tr>\
+  <tr class="element"><td>Lycée</td><td><input value="4" type="checkbox"></td></tr>\
   <tr class="element"><td>Professeurs</td><td><input value="5" type="checkbox"></td></tr>\
   <tr class="categorie"><td>Information invisible</td><td><input value="32" type="checkbox"></td></tr>\
   </tbody></table>',true);
@@ -1174,6 +1198,8 @@
   el.before('<a class="icon-annule" title="Annuler"></a><a class="icon-ok" title="Valider"></a>');
   el.next().addBack().hide();
   var form = $('<form></form>').appendTo(article).html($('#form-ajoutecolle').html());
+  // Ne pas quitter avec un textarea plein
+  $('textarea',form).on('change',function(e) { $('body').data('nepassortir',true); $(this).off(e); });
   $('textarea',form).textareahtml();  
   $('input',form).attr('id','cache');
   // Actions des boutons annulation, aide, validation
@@ -1243,6 +1269,13 @@
               if ( el.classList[1] != 'noreload' )
                 location.reload(true);
             }
+    }).done( function(data) {
+      // Cas spécial de la modification de son adresse électronique :
+      // envoi d'un code de confirmation à taper 
+      if ( data['etat'] == 'confirm_mail' )  {
+        $('[data-id="prefsperso|3"] p:first').html(data['message']).addClass('annonce');
+        $('[data-id="prefsperso|3"] p:hidden').show().children('input').attr('disabled',false);
+      }
     });
   else
     affiche('<p>Aucune donnée envoyée.</p>','nok');
@@ -1259,6 +1292,8 @@
   <a class="icon-aide" title="Aide pour ce formulaire"></a>\
   <a class="icon-ok" title="Valider"></a></article>').insertBefore($('article,#calendrier,#parentsdoc+*').first());
   var form = $('<form></form>').appendTo(article).html($('#form-'+idform).html());
+  // Ne pas quitter avec un textarea plein
+  $('textarea',form).on('change',function(e) { $('body').data('nepassortir',true); $(this).off(e); });
   // Facilités et peuplement du formulaire
   $('.edithtml',form).textareahtml();
   // Création de l'identifiant des champs à partir du name
@@ -1346,16 +1381,13 @@
     $('[data-parents*=",'+id+',"]', form).prop('disabled', true);
   }
   form.append('<input type="hidden" name="id" value="'+id+'">');
-  // Boutons 
+  // Bouton de vidage
   $('input[type="button"]', form).on("click", function() {
-    var action = ( this.value.substring(0,4) == 'Prop' ) ? 'propage' : 'vide';
     var contexte = $(this).parent().find('em').text();
-    var texte = ( action == 'propage' ) ? 'Vous allez propager le réglage d\'accès du répertoire <em>'+contexte+'</em> à l\'ensemble de ses sous-répertoires et des documents qu\'ils contiennent.<br>Vous pourrez modifier à nouveau le réglage de chaque document ou répertoire, de façon individuelle.'
-                                        : 'Vous allez vider le répertoire <em>'+contexte+'</em>. Cela supprimera définitivement l\'ensemble de ses sous-répertoires et des documents qu\'ils contiennent.<br>Cette opération n\'est pas annulable.';
-    confirmation(texte,this,function(el) {
+    confirmation('Vous allez vider le répertoire <em>'+contexte+'</em>. Cela supprimera définitivement l\'ensemble de ses sous-répertoires et des documents qu\'ils contiennent.<br>Cette opération n\'est pas annulable.',this,function(el) {
       $.ajax({url: 'ajax.php',
               method: "post",
-              data: 'action=reps&id='+id+'&'+action+'=1',
+              data: {action: 'reps', id: id, vide: 1 },
               dataType: 'json',
               el: '',
               fonction: function(el) {
@@ -1727,7 +1759,7 @@
     $('#id').val(el.parent().data('id').split('|')[1]);
     $('#jour').val($('td:eq(0)',tr).text().replace(/(.{6})(.{2})/,function(tout,x,y) {return x+'20'+y; }));
     $('#heure').val($('td:eq(1)',tr).text().replace('-',''));
-    $('#duree').val($('td:eq(3)',tr).text());
+    $('#duree').val($('td:eq(3)',tr).text().replace(/.*m/,function(s) {return '0h'+s.slice(0,-1); }));
   }
 }
 
@@ -1738,7 +1770,7 @@
     var f = $('#epingle form');
     var a = $('#autorisation', f).val();
     if ( a == 0 ) {
-      $('.affichesiinvite,.affichesiinvitation,.affichesimotdepasse,.mailenvoi,.mailliste', f).hide(0);
+      $('.affichesiinvite,.affichesiinvitation,.affichesimotdepasse', f).hide(0);
       $('textarea', f).prop('disabled',true).attr('placeholder','Zone de saisie des utilisateurs\nSélectionnez d\'abord un type d\'utilisateur');
     }
     else {
@@ -1748,9 +1780,6 @@
       $('.affichesiinvite', f).toggle(inv);
       $('.affichesiinvitation', f).toggle(!inv && !mdp);
       $('.affichesimotdepasse', f).toggle(!inv && mdp);
-      $('.mailenvoi', f).toggle(!inv);
-      $('.mailliste', f).toggle(a>2);
-      $('#mailenvoi', f).prop('disabled',mdp).change();
       $('textarea', f).prop('disabled',false).attr('placeholder',function() {
         if ( inv )       return 'identifiant_1,motdepasse_1\nidentifiant_2,motdepasse_2\nidentifiant_3,motdepasse_3\n...';
         else if ( mdp )  return 'nom_1,prénom_1,motdepasse_1\nnom_2,prénom_2,motdepasse_2\nnom_3,prénom_3,motdepasse_3\n...';
@@ -1758,9 +1787,6 @@
       });
     }
   }).change();
-  $('#epingle #mailenvoi').on("change",function() {
-    $('#epingle #mailliste').attr('disabled',!this.checked || this.disabled);
-  }).change();
 }
 
 // Facilités spécifiques de modification des événements
@@ -1876,11 +1902,7 @@
         $(this).find('input').click();
     });
     // Mise en évidence
-    $('input', f).on("change", function () {
-      $(this).parent().parent().removeClass('sel');
-      if ( this.checked )
-        $(this).parent().parent().addClass('sel');
-    });
+    $('input', f).on("change", function () { $(this).parent().parent().toggleClass('sel',this.checked); });
     // Validation
     $('.icon-ok', f).on("click", function() {
       // Mise à jour du select, valeur passée sous forme d'array
@@ -1902,19 +1924,60 @@
   $(this).toggleClass('icon-cocher icon-decocher').parent().parent().nextUntil('.categorie').find('input').prop('checked',$(this).hasClass('icon-decocher')).change();
 }
 
+// Édition d'un compte utilisateur (utilisateurs.php et utilisateurs-mails.php)
+function edite_utilisateur() {
+  var id = $(this).parent().parent().data('id');
+  // Récupération des données associées au compte
+  $.ajax({url: 'recup.php',
+          method: "post",
+          data: { action:'prefs', id:id },
+          dataType: 'json',
+          afficheform: function(data) {
+            if ( 'nom' in data ) {
+              popup($('#form-edite').html(),true);
+              var f = $('#fenetre');
+              // Création de l'identifiant des champs à partir du name
+              $('input[name]',f).attr('id',function(){ return this.getAttribute('name'); });
+              // Suppression des paragraphes et des questions non valables
+              if ( data['valide'] )             $('#comptedesactive, #demande, #invitation', f).remove();
+              else if ( data['demande'] )       $('#compteactif, #comptedesactive, #invitation', f).remove();
+              else if ( data['invitation'] )    $('#compteactif, #comptedesactive, #demande', f).remove();
+              else                              $('#compteactif, #demande, #invitation', f).remove();
+              if ( data['autorisation'] == 1 )    $('#nom, #prenom, #mail1, #mail2', f).parent().remove();
+              // Personalisation du premier paragraphe
+              $('p:first', f).html(function(i,code){ return code.replace('XXX', data['prenom'].length ? 'de <em>'+data['prenom']+' '+data['nom']+'</em>' : '<em>'+data['login']+'</em>')
+                                                                .replace('YYY','<em>'+['Invité','Élève','Colleur','Lycée','Professeur'][data['autorisation']-1]+'</em>'); });
+              // Peuplement du formulaire
+              $('input[type="text"],input[type="email"]',f).val(function(){ return data[this.id]; });
+              $('input[type="checkbox"]',f).prop("checked",function(){ return data[this.id]; });
+              if ( !data['mailenvoi'] )
+                $('[name="mailexp"],[name="mailcopie"]', f).parent().remove();
+              // Envoi par clic sur l'icône
+              $('a.icon-ok', f).on("click", function() {
+                $.ajax({url: 'ajax.php',
+                        method: "post",
+                        data: 'action=utilisateur&modif=prefs&id='+id+'&'+$('form', f).serialize(),
+                        dataType: 'json',
+                        el: '',
+                        fonction: function(el) {
+                          location.reload(true);
+                        }
+                });
+              });
+              // Envoi par appui sur Entrée
+              $('input', f).on('keypress',function (e) {
+                if ( e.which == 13 ) {
+                  e.preventDefault();
+                  $('a.icon-ok', f).click();
+                }
+              });
+            }
+          }
+        });
+}
+
 // Initialisation du tableau des utilisateurs
 function init_utilisateurs() {
-  // Affichage des icônes d'envoi de mail dans le tableau utilisateurs
-  // La case de tableau HTML contient la valeur 1 pour oui 0 pour non.
-  $('.icones.mailenvoi').each( function() {
-    this.innerHTML = ( this.textContent == 1 ) ? '<a class="icon-ok" title="Supprimer la possibilité d\'envoyer des courriels"></a>'
-                                               : '<a class="icon-nok" title="Accorder la possibilité d\'envoyer des courriels"></a>';
-  });
-  $('.mailenvoi a').on("click", mail_utilisateur);
-
-  // Modification multiple des préférences d'envoi de mail
-  $('th .icon-mail').on("click", mail_utilisateurs);
-
   // Icônes de cochage multiple
   $('.icon-cocher').on("click", cocher_utilisateurs);
 
@@ -1928,97 +1991,19 @@
   $('th .icon-desactive, th .icon-active, th .icon-supprutilisateur, th .icon-validutilisateur').on("click", modif_utilisateurs);
 
   // Clic sur toute la ligne (premières cases seulement)
-  $('td:not(.icones)').on("click",function(e) {
-    $(this).parent().find('input').click();
-  });
+  $('td:not(.icones)').on("click",function() { $(this).parent().find('input').click(); });
 
   // Mise en évidence
-  $('#utilisateurs input').on("change", function () {
-    $(this).parent().parent().removeClass('sel');
-    if ( this.checked )
-      $(this).parent().parent().addClass('sel');
-  });
+  $('#u input').on("change", function () { $(this).parent().parent().toggleClass('sel',this.checked); });
   
   /////////////
   // Fonctions
 
-  // Modification de la propriété d'envoi de courriels
-  function mail_utilisateur() {
-    var val = $(this).hasClass("icon-ok");
-    $.ajax({url: 'ajax.php',
-            method: "post",
-            data: { action:'utilisateur', modif:'mailenvoi', id:$(this).parent().parent().data('id'), val:1-val },
-            dataType: 'json',
-            el: $(this),
-            fonction: function(el) {
-              el.toggleClass('icon-ok icon-nok').attr("title",(val?'Accorder':'Supprimer')+' la possibilité d\'envoyer des courriels' );
-            }
-    });
-  }
-  
-  // Édition d'un compte utilisateur
-  function edite_utilisateur() {
-    var id = $(this).parent().parent().data('id');
-    // Récupération des données associées au compte
-    $.ajax({url: 'recup.php',
-            method: "post",
-            data: { action:'prefs', id:id },
-            dataType: 'json',
-            afficheform: function(data) {
-              if ( 'nom' in data ) {
-                popup($('#form-edite').html(),true);
-                var f = $('#fenetre');
-                // Création de l'identifiant des champs à partir du name
-                $('input[name]',f).attr('id',function(){ return this.getAttribute('name'); });
-                // Suppression des paragraphes et des questions non valables
-                if ( data['valide'] )             $('#comptedesactive, #demande, #invitation', f).remove();
-                else if ( data['demande'] )       $('#compteactif, #comptedesactive, #invitation', f).remove();
-                else if ( data['invitation'] )    $('#compteactif, #comptedesactive, #demande', f).remove();
-                else                              $('#compteactif, #demande, #invitation', f).remove();
-                if ( data['autorisation'] == 2 )         $('#mailliste', f).parent().remove();
-                else if ( data['autorisation'] == 1 )    $('#mailenvoi, #mailexp, #mailcopie, #mailliste', f).parent().remove();
-                // Personalisation du premier paragraphe
-                $('p:first', f).html(function(i,code){ return code.replace('XXX', data['prenom'].length ? 'de <em>'+data['prenom']+' '+data['nom']+'</em>' : '<em>'+data['login']+'</em>')
-                                                                  .replace('YYY','<em>'+['Invité','Élève','Colleur','Administratif','Professeur'][data['autorisation']-1]+'</em>'); });
-                // Peuplement du formulaire
-                $('input[type="text"],input[type="email"]',f).val(function(){ return data[this.id]; });
-                $('input[type="checkbox"]',f).prop("checked",function(){ return data[this.id]; });
-                // Comportement dynamique des propriétés d'envoi de courriels
-                $('#mailenvoi', f).on("click", function() {
-                  $('#mailexp, #mailcopie, #mailliste', f).prop('disabled',!this.checked);
-                  if ( this.checked && !$('#mailexp', f).val() )
-                    $('#mailexp', f).val(data['prenom']+' '+data['nom'])
-                });
-                $('#mailexp, #mailcopie, #mailliste', f).prop('disabled',!$('#mailenvoi', f).prop('checked'));
-                // Envoi par clic sur l'icône
-                $('a.icon-ok', f).on("click", function() {
-                  $.ajax({url: 'ajax.php',
-                          method: "post",
-                          data: 'action=utilisateur&modif=prefs&id='+id+'&'+$('form', f).serialize(),
-                          dataType: 'json',
-                          el: '',
-                          fonction: function(el) {
-                            location.reload(true);
-                          }
-                  });
-                });
-                // Envoi par appui sur Entrée
-                $('input', f).on('keypress',function (e) {
-                  if ( e.which == 13 ) {
-                    e.preventDefault();
-                    $('a.icon-ok', f).click();
-                  }
-                });
-              }
-            }
-          });
-  }
-  
   // Désactivation, réactivation, suppression, validation d'un compte utilisateur
   function modif_utilisateur() {
     var question = '';
-    var compte = $(this).parent().siblings().first().text();
-    compte = ( compte.length ) ? 'de <em>'+compte+'</em>' : 'd\'identifiant <em>'+$(this).parent().siblings().first().next().text()+'</em>';
+    var nom = $(this).parent().siblings().first();
+    var compte = ( nom.text().length ) ? 'de <em>'+nom.next().text()+' '+nom.text()+'</em>' : 'd\'identifiant <em>'+nom.next().next().text()+'</em>';
     var categorie = $(this).parent().parent().prevUntil('.categorie').last().prev().text().split(' ')[0];
     switch ( this.className.substring(5) ) {
       case 'desactive':
@@ -2042,8 +2027,8 @@
         }
         else if ( categorie == 'Professeurs' )
           question = 'Vous allez supprimer le compte professeur '+compte+'. <strong>Cela signifie que toutes les préférences de ce compte seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.<br> Les données des matières auxquelles il est associé sont indépendantes&nbsp;: elles ne seront pas supprimées.';
-        else if ( categorie == 'Administratifs' )
-          question ='Vous allez supprimer le compte administratif '+compte+'. Cela signifie que toutes les préférences de ce compte seront perdues.';
+        else if ( categorie == 'Lycée' )
+          question ='Vous allez supprimer le compte lycée '+compte+'. Cela signifie que toutes les préférences de ce compte seront perdues.';
         else if ( categorie == 'Colleurs' )
           question = 'Vous allez supprimer le compte colleur '+compte+'. <strong>Cela signifie que toutes les préférences de ce compte seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';
         else if ( categorie == 'Élèves' )
@@ -2071,27 +2056,6 @@
     });
   }
   
-  // Modification multiple de la propriété d'envoi de courriels pour plusieurs comptes
-  function mail_utilisateurs() {
-    var cases = $(this).parent().parent().nextUntil('.categorie').find(':checked');
-    if ( cases.length == 0 ) {
-      affiche('<p>Aucune case n\'est cochée, aucune action ne peut être réalisée.</p>','nok');
-      return
-    }
-    var ids = cases.map(function() { return $(this).parent().parent().data('id'); }).get().join(',');
-    var tds = cases.parent().prev().prev();
-    var val = ( tds.find('.icon-ok').length >= tds.find('.icon-nok').length ) ? 0 : 1;
-    $.ajax({url: 'ajax.php',
-            method: "post",
-            data: { action:'utilisateurs', modif:'mailenvoi', ids:ids, val:val },
-            dataType: 'json',
-            el: '',
-            fonction: function() {
-              location.reload(true);
-            }
-    });
-  }
-  
   // Désactivation, réactivation, suppression, validation multiple de comptes utilisateurs
   function modif_utilisateurs() {
     var cases = $(this).parent().parent().nextUntil('.categorie').find(':checked');
@@ -2099,10 +2063,11 @@
       affiche('<p>Aucune case n\'est cochée, aucune action ne peut être réalisée.</p>','nok');
       return
     }
-    var ids = cases.map(function() { return $(this).parent().parent().data('id'); }).get().join(',');
-    var comptes = cases.map(function() {
-      var compte = $(this).parent().siblings().first().text();
-      return ( compte.length ) ? '<em>'+compte+'</em>' : '<em>'+$(this).parent().siblings().first().next().text()+'</em>';
+    var lignes = cases.parent().parent();
+    var ids = lignes.map(function() { return $(this).data('id'); }).get().join(',');
+    var comptes = lignes.map(function() {
+      var nom = $(this).children().first().text();
+      return ( nom.length ) ? '<em>'+$(this).children().eq(1).text()+' '+nom+'</em>' : '<em>'+$(this).children().eq(2).text()+'</em>';
     }).get().join(', ');
     var pos = comptes.lastIndexOf(',');
     if ( pos > 0 )
@@ -2132,8 +2097,8 @@
         }
         else if ( categorie == 'Professeurs' )
           question = 'Vous allez supprimer les comptes professeurs de '+comptes+'. <strong>Cela signifie que toutes les préférences de ces comptes seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.<br> Les données des matières auxquelles ces utilisateurs sont associés sont indépendantes&nbsp;: elles ne seront pas supprimées.';
-        else if ( categorie == 'Administratifs' )
-          question ='Vous allez supprimer les comptes administratifs de '+comptes+'. Cela signifie que toutes les préférences de ces comptes seront perdues.';
+        else if ( categorie == 'Lycée' )
+          question ='Vous allez supprimer les comptes lycée de '+comptes+'. Cela signifie que toutes les préférences de ces comptes seront perdues.';
         else if ( categorie == 'Colleurs' )
           question = 'Vous allez supprimer les comptes colleurs de '+comptes+'. <strong>Cela signifie que toutes les préférences de ces comptes seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';
         else if ( categorie == 'Élèves' )
@@ -2168,27 +2133,23 @@
   // Affichage des icônes d'association
   // La case de tableau HTML contient deux valeurs séparées de "|" :
   // l'identifiant de la matière et la valeur 1 pour oui 0 pour non.
-  $('tbody tr:not(.categorie) td:not(:first-child,:last-child)').each( function() {
+  $('tr:not(.categorie) td:not(:first-child,:last-child)').each( function() {
       var valeurs = this.textContent.split('|');
       this.innerHTML = ( valeurs[1] == 1 ) ? '<a class="icon-ok" data-id="'+valeurs[0]+'" title="Supprimer l\'association à la matière"></a>'
                                            : '<a class="icon-nok" data-id="'+valeurs[0]+'" title="Établir l\'association à la matière"></a>';
   });
-  $('tbody tr:not(.categorie) a').on("click", association_um);
+  $('#umats a').on("click", association_um);
   
   // Icônes de cochage multiple
   $('.categorie [data-id]').on("click", association_ums).hide(0);
   $('.icon-cocher').on("click", cocher_utilisateurs).on("click",majicones)
   $('input[type="checkbox"]').on("click", majicones).on("change", function() {
     // Mise en évidence
-    $(this).parent().parent().removeClass('sel');
-    if ( this.checked )
-      $(this).parent().parent().addClass('sel');
+    $(this).parent().parent().toggleClass('sel',this.checked);
   });;
   
   // Clic sur la case de nom pour cocher
-  $('td:first-child').on("click",function() {
-    $(this).parent().find('input').click();
-  });
+  $('td:first-child').on("click",function() { $(this).parent().find('input').click(); });
 
   // Mise à jour des icônes de modifications multiples
   function majicones() {
@@ -2198,16 +2159,15 @@
       tr = tr.prevAll('.categorie').first();
     // Cases cochées
     var cases = tr.nextUntil('.categorie').find(':checked');
-    if ( cases.length == 0 ) {
+    if ( cases.length == 0 )
       $('[data-id]',tr).hide(0);
-      return
-    }
-    $('[data-id]',tr).each( function() {
-      var avant = $(this).hasClass("icon-ok");
-      var apres = cases.parent().prevAll().find('.icon-ok[data-id="'+this.getAttribute('data-id')+'"]').length < cases.length/2;
-      if ( avant != apres )
-        $(this).toggleClass('icon-ok icon-nok').attr('title', (apres?'Établir':'Supprimer')+' l\'association à la matière de tous les cochés');
-    }).show(0);
+    else
+      $('[data-id]',tr).each( function() {
+        var avant = $(this).hasClass("icon-ok");
+        var apres = cases.parent().prevAll().find('.icon-ok[data-id="'+this.getAttribute('data-id')+'"]').length < cases.length/2;
+        if ( avant != apres )
+          $(this).toggleClass('icon-ok icon-nok').attr('title', (apres?'Établir':'Supprimer')+' l\'association à la matière de tous les cochés');
+      }).show(0);
   }
 
   // Fonction d'association unique
@@ -2231,8 +2191,9 @@
       affiche('<p>Aucune case n\'est cochée, aucune action ne peut être réalisée.</p>','nok');
       return
     }
-    var ids = cases.map(function() { return $(this).parent().parent().data('id'); }).get().join(',');
-    var comptes = cases.map(function() { return $(this).parent().siblings().first().text().split('(')[0].trim(); }).get().join(', ');
+    var lignes = cases.parent().parent();
+    var ids = lignes.map(function() { return $(this).data('id'); }).get().join(',');
+    var comptes = lignes.children(':first-of-type').map(function() { return $(this).text().split('(')[0].trim(); }).get().join(', ');
     var pos = comptes.lastIndexOf(',');
     if ( pos > 0 )
       comptes = comptes.substring(0,pos)+' et'+comptes.substring(pos+1);
@@ -2254,6 +2215,55 @@
   
 }
 
+// Initialisation du tableau des autorisation d'envoi de courriels
+// et du tableau d'édition des adresses électroniques
+function init_envoimails() {
+  
+  var t = $('#envoimails');
+  // Affichage des icônes de validation
+  // La case de tableau HTML contient deux valeurs séparées de "|" :
+  // l'identifiant du groupe de réception et la valeur 1 pour oui 0 pour non.
+  // Le groupe d'émission est le data-id de la ligne.
+  $('td',t).each( function() {
+      var valeurs = this.textContent.split('|');
+      this.innerHTML = ( valeurs[1] == 1 ) ? '<a class="icon-ok" data-id="'+valeurs[0]+'" title="Supprimer l\'autorisation d\'envoi"></a>'
+                                           : '<a class="icon-nok" data-id="'+valeurs[0]+'" title="Établir l\'autorisation d\'envoi"></a>';
+  });
+
+  // Icônes de validation simple
+  $('td a',t).on("click", function() {
+    var val = $(this).hasClass("icon-nok")|0;
+    $.ajax({url: 'ajax.php',
+            method: "post",
+            data: { action:'prefsglobales', mails:1, depuis:$(this).parent().parent().data('id'), vers:$(this).data('id'), val:val },
+            dataType: 'json',
+            el: $(this),
+            fonction: function(el) {
+              el.toggleClass('icon-ok icon-nok').attr('title', (val?'Établir':'Supprimer')+' l\'autorisation d\'envoi');
+            }
+    });
+  });
+
+  // Icônes de validation multiple
+  $('th span',t).on("click", function() {
+    var val = $(this).hasClass("icon-ok");
+    var ligne = $(this).parent().parent();
+    $.ajax({url: 'ajax.php',
+            method: "post",
+            data: { action:'prefsglobales', mails:1, depuis:ligne.data('id'), vers:0, val:val|0 },
+            dataType: 'json',
+            el: ligne,
+            fonction: function(el) {
+              el.find('td a').toggleClass('icon-ok',val).toggleClass('icon-nok',!val).attr('title', (val?'Établir':'Supprimer')+' l\'autorisation d\'envoi');
+            }
+    });
+  });
+  
+  // Édition de comptes uniques
+  $('#umails .icon-edite').on("click", edite_utilisateur);
+  
+}
+
 // Édition des utilisateurs associés à un groupe
 function init_utilisateurs_groupes() {
   // Cases à cocher : utilisation des groupes pour les mails et/ou les notes
@@ -2279,7 +2289,7 @@
   var f = $('#fenetre');
   var span = $(this);
   article = span.parent().parent();
-  $('table', f).attr('id','utilisateurs');
+  $('table', f).attr('id','ugrp');
 
   // Modification du groupe indiqué en titre
   $('h3', f).append($('.editable', article).text() || $('input:first', article).val());
@@ -2297,11 +2307,7 @@
   });
 
   // Mise en évidence
-  $('input', f).on("change", function () {
-    $(this).parent().parent().removeClass('sel');
-    if ( this.checked )
-      $(this).parent().parent().addClass('sel');
-  });
+  $('input', f).on("change", function () { $(this).parent().parent().toggleClass('sel',this.checked); });
   
   // Sélection automatique des utilisateurs déjà choisis
   var ids = span.data('uids');
@@ -2368,7 +2374,6 @@
 function destinatairesmail() {
   popup($('#form-destinataires').html(),true);
   var f = $('#fenetre');
-  $('table', f).attr('id','utilisateurs');
   
   // Pliage/dépliage (les spans ont déjà été ajoutés)
   $('.icon-deplie', f).on("click", plie)
@@ -2384,11 +2389,10 @@
   
   // Décochage automatique de l'autre case du même utilisateur et mise en évidence
   $('input', f).on("change", function () {
-    var tr = $(this).parent().parent().removeClass('sel');
+    var tr = $(this).parent().parent();
     if ( this.checked )
       tr.find('input:not(.'+this.className+')').prop("checked",false);
-    if ( tr.find('input:checked').length )
-      tr.addClass('sel');
+    tr.toggleClass('sel',tr.find('input:checked').length>0);
   });
   
   // Sélection automatique des utilisateurs déjà choisis
@@ -2477,10 +2481,12 @@
 $(document).ajaxSend( function(ev,xhr,settings) {
               $('#load').show(200);
               // Sécurité anti XSS : Ajout du token CSRF
-              if ( settings.data.append )
-                settings.data.append('csrf-token',$('body').attr('data-csrf-token'));
-              else
-                settings.data = 'csrf-token='+$('body').attr('data-csrf-token')+'&'+settings.data;
+              if ( $('body').attr('data-csrf-token') != undefined )  {
+                if ( settings.data.append )
+                  settings.data.append('csrf-token',$('body').attr('data-csrf-token'));
+                else
+                  settings.data = 'csrf-token='+$('body').attr('data-csrf-token')+'&'+settings.data;
+              }
             })
            .ajaxStop( function() {
               $('#load').hide(200);
@@ -2490,6 +2496,7 @@
               switch ( data['etat'] ) {
                 // Si ok, on l'affiche dans le log et on lance la "fonction" de mise à jour de l'affichage
                 case 'ok':
+                  $('body').data('nepassortir',false);
                   affiche(data['message'],'ok');
                   settings.fonction(settings.el);
                   break;
@@ -2538,7 +2545,7 @@
   $('.editable').editinplace();
 
   // Déconnexion
-  $('a.icon-deconnexion').on('click',function(e) {
+  $('a.icon-deconnexion').on("click",function(e) {
     $.ajax({url: 'ajax.php',
             method: "post",
             data: { action:'deconnexion' },
@@ -2550,6 +2557,38 @@
     });
   });
 
+  // Menu mobile
+  $('.icon-menu').on("click", function(e) {
+    e.stopPropagation();
+    $('nav').toggleClass('visible');
+    if ( $('nav').hasClass('visible') )  {
+      $('<div id="menu_fond"></div>').appendTo('body');
+      $('#menu_fond').on("click", function() {
+        $('#menu_fond').remove();
+        $('nav').removeClass('visible');
+      });
+    }
+    else 
+      $('#menu_fond').remove();
+  });
+  
+  // Changement de Cahier si interface globale et si compte global existant contenant au moins un autre Cahier
+  $('a.icon-echange').on("click",function() {
+    $.ajax({url: 'recup.php',
+            method: "post",
+            data: { action:'compteglobal' },
+            dataType: 'json',
+            afficheform: function(data) {
+              popup('<h3>Changer de Cahier</h3><div></div>',true);
+              var f = $('#fenetre');
+              // Récupération des valeurs et écriture 
+              var cahiers = data['cahiers'];
+              for ( var rep in cahiers )
+                $('div',f).attr('id','cahiers').append('<a href="/'+rep+'/">'+cahiers[rep]+'</a>');
+            }
+    });
+  });
+
   /////////////////////////////
   // Spécifique cahier de texte
 
@@ -2583,10 +2622,13 @@
   $('.supprmultiple').on("click", suppressionmultiple);
   
   // Gestion des utilisateurs
-  $('#utilisateurs').each(init_utilisateurs);
+  $('#u').each(init_utilisateurs);
   
   // Gestion des associations utilisateurs-matières
-  $('#utilisateurs-matieres').each(init_utilisateurs_matieres);
+  $('#umats').each(init_utilisateurs_matieres);
+
+  // Gestion des autorisations d'envoi de courriels
+  $('#envoimails').each(init_envoimails);
 
   // Édition des utilisateurs des groupes - fonction à ne lancer qu'une fois
   $('.usergrp').first().each(init_utilisateurs_groupes);
@@ -2606,9 +2648,11 @@
   // Spécifique relève de notes
   $('#relevenotes').on("click", relevenotes);
 
-  // Menu pour les petits écrans
-  $('.icon-menu').on("click", function() {
-    $('#colonne,nav').toggleClass('visible');
-  });
+  /////////////////////////////
+  // Ne pas quitter avec un textarea plein
+  $('body').data('nepassortir',false);
+  $('textarea:visible').on('change',function(e) { $('body').data('nepassortir',true); $(this).off(e); });
+  window.addEventListener('beforeunload', function (e) { if ( $('body').data('nepassortir') )  { e.preventDefault(); e.returnValue = ''; } });
 
 });
+
diff -urN cahier-de-prepa8.1.1/js/edition.min.js cahier-de-prepa9.0.0/js/edition.min.js
--- cahier-de-prepa8.1.1/js/edition.min.js	2018-11-11 00:24:14.529519147 +0100
+++ cahier-de-prepa9.0.0/js/edition.min.js	2019-08-28 19:37:35.077528715 +0200
@@ -1,3 +1,3 @@
-function affiche(message,etat){$("#log").removeClass().addClass(etat).html(message).append('<span class="icon-ferme"></span>').fadeIn().off("click").on("click",function(){window.clearTimeout(extinction);$(this).fadeOut(800)});extinction=window.setTimeout(function(){$("#log").fadeOut(800)},6e3)}function reconnect(settings,light){$("#fenetre,#fenetre_fond").remove();if(settings.url=="recup.php")var action=settings.data.indexOf("prefs")?"récupérer les préférences de cet utilisateur":"récupérer la liste des répertoires et documents disponibles";else{var action="valider cette action";settings.afficheform=Function.prototype}if(light)popup('<a class="icon-ok" title="Valider"></a><h3>Connexion nécessaire</h3>           <p>Vous êtes déjà connecté, mais vous devez saisir de nouveau votre mot de passe pour '+action+'.</p>           <form>           <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepasse"></p>           </form>',true);else popup('<a class="icon-ok" title="Valider"></a><h3>Connexion nécessaire</h3>           <p>Vous avez été automatiquement déconnecté. Vous devez vous connecter à nouveau pour '+action+'.</p>           <form>           <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" name="login" id="login"></p>           <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepasse"></p>           </form>',true);$("#fenetre input:first").focus();$("#fenetre a.icon-ok").on("click",function(){$.ajax({url:settings.url,method:"post",data:$("#fenetre form").serialize()+"&"+settings.data,dataType:"json",el:settings.el,afficheform:settings.afficheform,fonction:settings.fonction}).done(function(data){if(data["etat"]!="mdpnok")$("#fenetre,#fenetre_fond").remove()})});$("#fenetre a.icon-ferme").on("click",function(){affiche("Modification non effectuée, connexion nécessaire","nok")});$("#fenetre input").on("keypress",function(e){if(e.which==13){$("#fenetre a.icon-ok").click();return false}})}function popup(contenu,modal){$("#fenetre,#fenetre_fond").remove();var el=$('<article id="fenetre"></article>').appendTo("body").html(contenu).focus();if(modal)$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});else $('<a class="icon-epingle" title="Épingler à la page"></a>').prependTo(el).on("click",function(){$("#fenetre_fond").remove();$(this).remove();el.removeAttr("id").insertBefore($("article,#calendrier,#parentsdoc+*").first())});$('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function(){el.remove();$("#fenetre_fond").remove()})}function confirmation(question,element,action){popup("<h3>Demande de confirmation</h3><p>"+question+'</p><p class="confirmation"><button class="icon-ok"></button>&nbsp;&nbsp;&nbsp;<button class="icon-annule"></button></p>',true);$("#fenetre .icon-ok").on("click",function(){action(element);$("#fenetre,#fenetre_fond").remove()});$("#fenetre .icon-annule").on("click",function(){$("#fenetre,#fenetre_fond").remove()})}function plie(){$(this).parent().parent().nextUntil(".categorie").fadeToggle("slow");$(this).toggleClass("icon-plie icon-deplie")}$.fn.textareahtml=function(){this.each(function(){var ta=$(this);var placeholder=this.getAttribute("placeholder");this.setAttribute("placeholder",placeholder+". Formattage en HTML, balises visibles.");var ce=$('<div contenteditable="true" placeholder="'+placeholder+'"></div>').insertAfter(ta.before(boutons)).hide();var boutonretour=ta.prev().children(".icon-retour");if(ta.hasClass("ligne")){ce.addClass("ligne");ta.prev().addClass("ligne")}ta.on("keypress",function(e){if(e.which==13)this.value=nettoie(this.value)}).on("paste cut",function(){var el=this;setTimeout(function(){el.value=nettoie(el.value)},100)});ce.on("keypress",function(e){if(e.which==13)boutonretour.click()}).on("paste cut",function(){var el=this;setTimeout(function(){el.innerHTML=nettoie(el.innerHTML)+"<br>"},100)});ta.prev().children(".icon-nosource").on("click",function(e){e.preventDefault();ta.hide();ce.show().css("min-height",ta.outerHeight());$(this).hide().prev().show();ce.focus().html(nettoie(ta.val())).change();if(window.getSelection){var r=document.createRange();r.selectNodeContents(ce[0]);r.collapse(false);var s=window.getSelection();s.removeAllRanges();s.addRange(r)}else{var r=document.body.createTextRange();r.moveToElementText(ce[0]);r.collapse(false);r.select()}});ta.prev().children(".icon-source").on("click",function(e){e.preventDefault();ce.hide(0);ta.show(0).css("height",ce.height());$(this).hide().next().show();ta.focus().val(nettoie(ce.html()))}).hide();ta.prev().children(".icon-aide").on("click",function(e){e.preventDefault();aidetexte()});ta.prev().children().not(".icon-nosource,.icon-source,.icon-aide").on("click",function(e){e.preventDefault();window["insertion_"+this.className.substring(5)]($(this))})})};$.fn.editinplace=function(){this.each(function(){var el=$(this);el.data("original",el.is("h3")?el.text():el.html());$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transforme)})};function transforme(){var el=$(this).parent().addClass("avecform");if(el.is("div"))el.html('<form><textarea name="val" rows="'+(el.data("original").split(/\r\n|\r|\n/).length+3)+'"></textarea></form>');else el.html('<form class="edition" onsubmit="$(this).children(\'a.icon-ok\').click(); return false;"><input type="text" name="val" value=""></form>');var input=el.find('[name="val"]').val(el.data("original")).attr("placeholder",el.attr("placeholder"));if(el.hasClass("edithtml"))input.textareahtml();$('<a class="icon-ok" title="Valider"></a>').appendTo(el.children()).on("click",function(){var id=el.data("id").split("|");if(el.hasClass("edithtml"))input.val(nettoie(input.is(":visible")?input.val():input.next().html()));$.ajax({url:"ajax.php",method:"post",data:{action:id[0],champ:id[1],id:id[2],val:input.val()},dataType:"json",el:el,fonction:function(el){var val=el.find('[name="val"]').val();el.removeClass("avecform").html(val).data("original",val);$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transforme)}})});$('<a class="icon-annule" title="Annuler"></a>').appendTo(el.children()).on("click",function(){el.removeClass("avecform").html(el.data("original"));$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transforme)});input.focus().val(el.hasClass("edithtml")?nettoie(input.val()):input.val())}$.fn.editinplacecdt=function(){this.each(function(){$(this).wrapInner("<span></span>").data("original",$(this).text());$('<a class="icon-edite" title="Modifier"></a>').appendTo($(this)).on("click",transformecdt)})};function transformecdt(){var el=$(this).parent();$(".icon-edite",el).remove();var form=$('<form class="titrecdt"></form>').insertBefore(el.parent().children("div")).html($("#form-cdt").html());$("input, select",form).attr("id",function(){return this.getAttribute("name")});var valeurs=el.data("donnees");for(var cle in valeurs)$("#"+cle).val(valeurs[cle]);form.init_cdt_boutons();$("input,#demigroupe",form).on("change keyup",function(){var t=new Date($("#jour").val().replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));var dg=$("#demigroupe").val()==1?" (en demi-groupe)":"";switch(parseInt(seances[$("#tid").val()])){case 0:var titre=jours[t.getDay()]+" "+$("#jour").val()+" à "+$("#h_debut").val()+" : "+$("#tid option:selected").text()+dg;break;case 1:var titre=jours[t.getDay()]+" "+$("#jour").val()+" de "+$("#h_debut").val()+" à "+$("#h_fin").val()+" : "+$("#tid option:selected").text()+dg;break;case 2:var titre=jours[t.getDay()]+" "+$("#jour").val()+" : "+$("#tid option:selected").text()+" pour le "+$("#pour").val()+dg;break;case 3:var titre=jours[t.getDay()]+" "+$("#jour").val()+" : "+$("#tid option:selected").text()+dg;break;case 4:var titre=jours[t.getDay()]+" "+$("#jour").val();break;case 5:var titre="[Entrée hebdomadaire]"}$("span",el).text(titre)});$('<a class="icon-ok" title="Valider"></a>').appendTo(el).on("click",function(){var id=el.parent().data("id").split("|");$.ajax({url:"ajax.php",method:"post",data:"action=cdt-elems&id="+id[1]+"&"+form.serialize(),dataType:"json",el:el,fonction:function(el){var form=el.siblings("form");el.data("original",$("span",el).text()).data("donnees",{tid:$("#tid").val(),jour:$("#jour").val(),h_debut:$("#h_debut").val(),h_fin:$("#h_fin").val(),pour:$("#pour").val(),demigroupe:$("#demigroupe").val()});form.remove();$("a",el).remove();$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transformecdt)}}).done(function(data){if(data["etat"]=="ok"&&data["reload"]=="oui")location.reload(true)})});$('<a class="icon-annule" title="Annuler"></a>').appendTo(el).on("click",function(){form.remove();$("span",el).html(el.data("original"));$("a",el).remove();$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transformecdt)})}function nettoie(html){if(html.indexOf("cdptmp")>0){var tmp=$("<div>"+html+"</div>");tmp.find(".cdptmp").contents().unwrap();html=tmp.html();if(html.indexOf("cdptmp")>0)html=html.replace(/<span class="cdptmp"><\/span>/g,"")}return html.replace(/(<\/?[A-Z]+)([^>]*>)/g,function(tout,x,y){return x.toLowerCase()+y}).replace(/[\r\n ]+/g," ").replace(/(<br>)+[ ]?<\/(p|div|li|h)/g,function(tout,x,y){return"</"+y}).replace(/<br>/g,"<br>\n").replace(/<(p|div|li|h)/g,function(x){return"\n"+x}).replace(/<\/(p|div|li|h.)>/g,function(x){return x+"\n"}).replace(/<\/?(ul|ol)[^>]*>/g,function(x){return"\n"+x+"\n"}).replace(/^(?!(<p|<div|<ul|<ol|<li|<h))(.+)<br>$/gm,function(tout,x,y){return"<p>"+y+"</p>"}).replace(/^(?!(<(p|div|ul|ol|li)))[ ]?(.+)[ ]?$/gm,function(t,x,y,z){return z.match(/.*(p|div|ul|ol|li|h.)>$/)?z:"<p>"+z+"</p>"}).replace(/^[ ]?(<\/?(br|p|div|h.)>){0,2}[ ]?(<\/(p|div|h.)>)?[ ]?$/gm,"").replace(/^\n/gm,"").replace(/<li/g,"  <li")}function insert(el,debut,fin,milieu){var contenant=el.parent().siblings("textarea,[contenteditable]").filter(":visible")[0];if(!contenant.hasAttribute("data-selection"))marqueselection(el);var texte=milieu===undefined?debut+"Í"+contenant.getAttribute("data-selection")+"Ì"+fin:debut+"Í"+milieu+"Ì"+fin;var contenu=nettoie(contenant.getAttribute("data-contenu").replace(/Í.*Ì/,texte));if(contenant.tagName=="TEXTAREA")contenant.value=contenu.replace(/[ÍÌ]/g,"");else contenant.innerHTML=contenu.replace(/[ÍÌ]/g,"");marqueselection(el,true);if(contenant.tagName=="TEXTAREA"&&contenant.selectionStart!==undefined){contenant.selectionStart=contenu.indexOf("Í");contenant.selectionEnd=contenu.indexOf("Ì")-1;contenant.focus()}else if(document.selection){if(contenant.tagName!="TEXTAREA")contenu=contenu.replace(/(<([^>]+)>)[\n]*/g,"");range=document.body.createTextRange();range.moveToElementText(contenant);range.collapse(true);range.moveEnd("character",contenu.indexOf("Ì")-1);range.moveStart("character",contenu.indexOf("Í"));range.select()}else if(window.getSelection){contenant.innerHTML=contenu.replace("Í",'<span class="cdptmp">').replace("Ì","</span>")+"<br>";selection=window.getSelection();range=document.createRange();range.selectNodeContents($(contenant).find(".cdptmp")[0]);selection.removeAllRanges();selection.addRange(range);contenant.focus()}}function marqueselection(el,efface){var contenant=el.parent().siblings("textarea,[contenteditable]").filter(":visible")[0];if(efface){contenant.removeAttribute("data-selection");contenant.removeAttribute("data-contenu");return true}var original=contenant.tagName=="TEXTAREA"?contenant.value:contenant.innerHTML;var sel="";if(contenant.tagName=="TEXTAREA"&&contenant.selectionStart!==undefined){contenant.focus();sel=contenant.value.substring(contenant.selectionStart,contenant.selectionEnd);contenant.value=contenant.value.substr(0,contenant.selectionStart)+"Í"+sel+"Ì"+contenant.value.substring(contenant.selectionEnd)}else if(window.getSelection){var range=window.getSelection().getRangeAt(0);if(contenant==range.commonAncestorContainer||$.contains(contenant,range.commonAncestorContainer)){var sel=window.getSelection().toString();range.deleteContents();range.insertNode(document.createTextNode("Í"+sel+"Ì"))}}else{var range=document.selection.createRange();if(contenant==range.parentElement()||$.contains(contenant,range.parentElement())){var sel=document.selection.createRange().text;document.selection.createRange().text="Í"+sel+"Ì"}}if(contenant.tagName=="TEXTAREA"){var contenu=contenant.value;contenant.value=original}else{var contenu=contenant.innerHTML;$(contenant).html(original)}if(contenu.indexOf("Ì")<0)contenu=contenu+"ÍÌ";contenant.setAttribute("data-selection",sel);contenant.setAttribute("data-contenu",contenu);return sel}var boutons='<p class="boutons">  <button class="icon-titres" title="Niveaux de titres"></button>  <button class="icon-par1" title="Paragraphe"></button>  <button class="icon-par2" title="Paragraphe important"></button>  <button class="icon-par3" title="Paragraphe très important"></button>  <button class="icon-retour" title="Retour à la ligne"></button>  <button class="icon-gras" title="Gras"></button>  <button class="icon-italique" title="Italique"></button>  <button class="icon-souligne" title="Souligné"></button>  <button class="icon-omega" title="Insérer une lettre grecque"></button>  <button class="icon-sigma" title="Insérer un signe mathématique"></button>  <button class="icon-exp" title="Exposant"></button>  <button class="icon-ind" title="Indice"></button>  <button class="icon-ol" title="Liste énumérée"></button>  <button class="icon-ul" title="Liste à puces"></button>  <button class="icon-lien1" title="Lien vers un document du site"></button>  <button class="icon-lien2" title="Lien internet"></button>  <button class="icon-tex" title="LATEX!"></button>  <button class="icon-source" title="Voir et éditer le code html"></button>  <button class="icon-nosource" title="Voir et éditer le texte formaté"></button>  <button class="icon-aide" title="Aide pour cet éditeur de texte"></button></p>';function insertion_titres(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'un titre</h3>  <p>Choisissez le type du titre ci-dessous. Vous pouvez éventuellement modifier le texte (ou pourrez le faire ultérieurement). Il est conseillé d\'utiliser des titres de niveau 2 pour les titres dans les programmes de colle.</p>  <input type="radio" name="titre" id="t3" value="3" checked><h3><label for="t3">Titre de niveau 1 (pour les I,II...)</label></h3><br>  <input type="radio" name="titre" id="t4" value="4"><h4><label for="t4">Titre de niveau 2 (pour les 1,2...)</label></h4><br>  <input type="radio" name="titre" id="t5" value="5"><h5><label for="t5">Titre de niveau 3 (pour les a,b...)</label></h5><br>  <input type="radio" name="titre" id="t6" value="6"><h6><label for="t6">Titre de niveau 4</label></h6><br>  <p class="ligne"><label for="texte">Texte&nbsp;: </label><input type="text" id="texte" value="'+marqueselection(el)+'" size="80"></p>  <hr><h3>Aperçu</h3><div id="apercu"></div>',true);$("#fenetre input").on("click keyup",function(){var balise="h"+$("[name='titre']:checked").val();$("#apercu").html("<"+balise+">"+($("#texte").val().length?$("#texte").val():"Texte du titre")+"</"+balise+">")}).first().keyup();$("#texte").on("keypress",function(e){if(e.which==13)$("#fenetre a.icon-ok").click()}).focus();$("#fenetre a.icon-ok").on("click",function(){var balise="h"+$("[name='titre']:checked").val();insert(el,"<"+balise+">","</"+balise+">",$("#texte").val());$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_omega(el){popup("<h3>Insertion d'une lettre grecque</h3>  <p>Cliquez sur la lettre à insérer&nbsp;:</p>  <button>&alpha;</button> <button>&beta;</button> <button>&gamma;</button> <button>&Delta;</button> <button>&delta;</button> <button>&epsilon;</button> <button>&eta;</button> <button>&Theta;</button> <button>&theta;</button> <button>&Lambda;</button> <button>&lambda;</button> <button>&mu;</button> <button>&nu;</button> <button>&xi;</button> <button>&Pi;</button> <button>&pi;</button> <button>&rho;</button> <button>&Sigma;</button> <button>&sigma;</button> <button>&tau;</button> <button>&upsilon;</button> <button>&Phi;</button> <button>&phi;</button> <button>&Psi;</button> <button>&psi;</button> <button>&Omega;</button> <button>&omega;</button>",true);$("#fenetre button").on("click",function(){insert(el,"","",$(this).text());$("#fenetre,#fenetre_fond").remove()})}function insertion_sigma(el){popup("<h3>Insertion d'un symbole mathématique</h3>  <p>Cliquez sur le symbole à insérer&nbsp;:</p>  <button>&forall;</button> <button>&exist;</button> <button>&part;</button> <button>&nabla;</button> <button>&prod;</button> <button>&sum;</button> <button>&plusmn;</button> <button>&radic;</button> <button>&infin;</button> <button>&int;</button> <button>&prop;</button> <button>&sim;</button> <button>&cong;</button> <button>&asymp;</button> <button>&ne;</button> <button>&equiv;</button> <button>&le;</button> <button>&ge;</button> <button>&sub;</button> <button>&sup;</button> <button>&nsub;</button> <button>&sube;</button> <button>&supe;</button> <button>&isin;</button> <button>&notin;</button> <button>&ni;</button> <button>&oplus;</button> <button>&otimes;</button> <button>&sdot;</button> <button>&and;</button> <button>&or;</button> <button>&cap;</button> <button>&cup;</button> <button>&real;</button> <button>&image;</button> <button>&empty;</button> <button>&deg;</button> <button>&prime;</button> <button>&micro;</button> <button>&larr;</button> <button>&uarr;</button> <button>&rarr;</button> <button>&darr;</button> <button>&harr;</button> <button>&lArr;</button> <button>&uArr;</button> <button>&rArr;</button> <button>&dArr;</button> <button>&hArr;</button>",true);$("#fenetre button").on("click",function(){insert(el,"","",$(this).text());$("#fenetre,#fenetre_fond").remove()})}function insertion_ol(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'une liste numérotée</h3>  <p>Choisissez le type de numérotation et la valeur de départ de la liste ci-dessous. Vous pouvez éventuellement modifier les différents éléments en les écrivant ligne par ligne. Vous pourrez ajouter un élément ultérieurement en l\'encadrant par les balises &lt;li&gt; et &lt;/li&gt;.</p>  <p class="ligne"><label for="t1">Numérotation numérique (1, 2, 3...)</label><input type="radio" name="type" id="t1" value="1" checked></p>  <p class="ligne"><label for="t2">Numérotation alphabétique majuscule (A, B, C...)</label><input type="radio" name="type" id="t2" value="A"></p>  <p class="ligne"><label for="t3">Numérotation alphabétique minuscule (a, b, c...)</label><input type="radio" name="type" id="t3" value="a"></p>  <p class="ligne"><label for="t4">Numérotation romaine majuscule (I, II, III...)</label><input type="radio" name="type" id="t4" value="I"></p>  <p class="ligne"><label for="t5">Numérotation romaine minuscule (i, ii, iii...)</label><input type="radio" name="type" id="t5" value="i"></p>  <p class="ligne"><label for="debut">Valeur de début (numérique)</label><input type="text" id="debut" value="1"></p>  <p class="ligne"><label for="lignes">Textes (chaque ligne correspond à un élément de la liste)&nbsp;: </label></p>  <textarea id="lignes" rows="5">'+marqueselection(el)+'</textarea>  <hr><h3>Aperçu</h3><div id="apercu"></div>',true);$("#fenetre :input").on("click keyup",function(){var debut=$("#debut").val();debut=debut.length&&debut>1?' start="'+debut+'"':"";$("#apercu").html('<ol type="'+$("[name='type']:checked").val()+'"'+debut+"><li>"+($("#lignes").val().length?$("#lignes").val().trim("\n").replace(/\n/g,"</li><li>"):"Première ligne</li><li>Deuxième ligne</li><li>...")+"</li></ol>")}).first().keyup();$("#lignes").focus();$("#fenetre a.icon-ok").on("click",function(){var debut=$("#debut").val();debut=debut.length&&debut>1?' start="'+debut+'"':"";var elements=$("#lignes").val().trim("\n");var index=elements.lastIndexOf("\n");if(index>0){var dernier=elements.substring(index+1);elements=elements.substring(0,index)}else var dernier="";insert(el,'<ol type="'+$("[name='type']:checked").val()+'"'+debut+"><li>"+elements.replace(/\n/g,"</li><li>")+"</li><li>","</li></ol>",dernier);$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_ul(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'une liste à puces</h3>  <p>Vous pouvez éventuellement modifier les différents éléments en les écrivant ligne par ligne (chaque ligne correspond à un élément de la la liste). Vous pourrez ajouter un élément ultérieurement en l\'encadrant par les balises &lt;li&gt; et &lt;/li&gt;.</p>  <textarea id="lignes" rows="5">'+marqueselection(el)+'</textarea>  <hr><h3>Aperçu</h3><div id="apercu"></div>',true);$("#lignes").on("click keyup",function(){$("#apercu").html("<ul><li>"+($("#lignes").val().length?$("#lignes").val().trim("\n").replace(/\n/g,"</li><li>"):"Première ligne</li><li>Deuxième ligne</li><li>...")+"</li></ul>")}).keyup().focus();$("#fenetre a.icon-ok").on("click",function(){var elements=$("#lignes").val().trim("\n");var index=elements.lastIndexOf("\n");if(index>0){var dernier=elements.substring(index+1);elements=elements.substring(0,index)}else var dernier="";insert(el,"<ul><li>"+elements.replace(/\n/g,"</li><li>")+"</li><li>","</li></ul>",dernier);$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_lien1(el){var sel=marqueselection(el);popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'un lien vers un document de Cahier de Prépa</h3>  <div><p style="text-align:center; margin: 2em 0;">[Récupération des listes de documents]</p></div>  <div style="display:none;"><hr><h3>Aperçu</h3><div id="apercu" style="text-align:center;">[Veuillez choisir un document]</div></div>',true);$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)});$.ajax({url:"recup.php",method:"post",data:{action:"docs"},dataType:"json"}).done(function(data){var majapercu=function(){var apercu=$("#apercu");var id=$("#doc").val();var texte=$("#doc option:selected").text();if(id==0)apercu.html(texte);else if($("#vue").is(":checked")){var l=$("#largeur").val();if(texte.slice(-4,-1)=="pdf"){if(apercu.children(".pdf").length==0)apercu.html('<div><object data="download?id='+id+'" type="application/pdf" height="100%" width="100%"> <a href="download?id='+id+'">'+texte+"</a> </object></div>");else if(apercu.find("object").attr("data").substr(12)!=id)apercu.find("object").attr("data","download?id="+id).html('<a href="download?id='+id+'">'+texte+"</a>");apercu.children().attr("class","pdf "+$("#format").val());if(l){if(l==100)apercu.children().removeAttr("style").children().attr("width","100%").removeAttr("style");else{apercu.children().css("padding-bottom",$('<div class="'+$("#format").val()+'"></div>').css("padding-bottom").slice(0,-1)*l/100+"%");apercu.find("object").attr("width",l+"%").css("left",(100-l)/2+"%")}}}else if("jpgpegpng".indexOf(texte.slice(-4,-1))>-1){if(apercu.children("img").length==0)apercu.css("text-align","").html('<img src="download?id='+id+'">');else if(apercu.children().attr("src").substr(12)!=id)apercu.children().attr("src","download?id="+id);if(l){if(l==100)apercu.children().removeAttr("style");else apercu.children().css("width",l+"%").css("margin-left",(100-l)/2+"%")}}}else $("#apercu").css("text-align","center").html('<a onclick="return false;" href="download?id='+this.value+'">'+$("#texte").val()+"</a>")};var affichedocs=function(data){$("#fenetre > div:first").html('  <p>Choisissez ci-dessous le répertoire puis le document à insérer. Vous pouvez aussi modifier le texte visible. Cela reste modifiable ultérieurement&nbsp;: le texte est situé entre les deux balises &lt;a...&gt; et &lt;/a&gt;.</p>  <p class="ligne"><label for="mat">Matière&nbsp;:</label><select id="mat">'+data.mats+'</select></p>  <p class="ligne"><label for="rep">Répertoire&nbsp;:</label><select id="rep"></select></p>  <p class="ligne"><label for="doc">Document&nbsp;:</label><select id="doc"></select></p>  <p class="ligne"><label for="texte">Texte visible&nbsp;:</label><input type="text" id="texte" value="'+sel+'" size="80" data-auto="1"></p>  <p class="ligne"><label for="vue">Afficher dans la page (PDF et image uniquement)</label><input type="checkbox" id="vue">  <p class="ligne"><label for="largeur">Largeur en %&nbsp;:</label><input type="text" id="largeur" value="100" size="3"></p>  <p class="ligne"><label for="format">Format (PDF uniquement)</label><select id="format">    <option value="portrait">A4 vertical</option><option value="paysage">A4 horizontal</option><option value="hauteur50">Hauteur 50%</option>  </select>');$("#fenetre > div:last").show();if($("#texte").val().length)$("#texte").attr("data-auto",0);$("#doc").on("change keyup",function(e){if(e.which==13)$("#fenetre a.icon-ok").click();var texte=$("#doc option:selected").text();if($("#texte").attr("data-auto")==1)$("#texte").val(this.value>0?texte.substr(0,texte.lastIndexOf("(")-1):"---");if("pdfjpgpegpng".indexOf(texte.slice(-4,-1))>-1)$("#vue").change().parent().show();else{$("#vue, #largeur, #format").parent().hide();$("#vue").prop("checked",false)}majapercu()});$("#texte").on("change keypress",function(e){if(e.which==0)return;if(e.which==13)$("#fenetre a.icon-ok").click();if(this.value.length==0){$(this).data("auto",1);$("#doc").change()}else{$(this).data("auto",0);majapercu()}});$("#vue").on("change",function(){if($("#vue").is(":checked")){if($("#doc option:selected").text().slice(-4,-1)=="pdf"){$("#largeur, #format").parent().show();$("#texte").parent().hide()}else if("jpgpegpng".indexOf($("#doc option:selected").text().slice(-4,-1))>-1){$("#largeur").parent().show();$("#format, #texte").parent().hide()}}else{$("#texte").parent().show();$("#largeur, #format").parent().hide()}majapercu()});$("#format").on("change keyup",function(e){if(e.which==13)$("#fenetre a.icon-ok").click();majapercu()});$("#largeur").on("keydown",function(e){if(e.which==38)++this.value;else if(e.which==40)--this.value}).on("change keyup",function(e){if(e.which==0)return;if(e.which==13)$("#fenetre a.icon-ok").click();if(this.value!=$(this).data("valeur")){$(this).data("valeur",this.value);majapercu()}}).attr("data-valeur",100);$("#rep").on("change",function(){$("#doc").html(data.docs[this.value]).change()});$("#mat").on("change",function(){$("#rep").html(data.reps[this.value]).change()}).focus().change();$("#fenetre a.icon-ok").on("click",function(){if($("#doc").val()){if($("#vue").is(":checked")&&"pdfjpgpegpng".indexOf($("#doc option:selected").text().slice(-4,-1))>-1)insert(el,$("#apercu").html(),"","");else insert(el,'<a href="download?id='+$("#doc").val()+'">',"</a>",$("#texte").val());$("#fenetre,#fenetre_fond").remove()}});$("#mat option").each(function(){if($("body").attr("data-matiere")==this.value)$("#mat").val(this.value).change()})};if("mats"in data)affichedocs(data)})}function insertion_lien2(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'un lien</h3>  <p class="ligne"><label for="texte">Texte visible&nbsp;: </label><input type="text" id="texte" value="'+marqueselection(el)+'" size="80"></p>  <p class="ligne"><label for="url">Adresse&nbsp;: </label><input type="text" id="url" value="http://" size="80"></p>  <hr><h3>Aperçu</h3><div id="apercu" style="text-align:center;"></div>',true);$("#fenetre input").on("click keyup",function(){$("#apercu").html($("#texte").val().length?'<a onclick="return false;" href="'+$("#url").val()+'">'+$("#texte").val()+"</a>":"[Écrivez un texte visible]")}).on("keypress",function(e){if(e.which==13)$("#fenetre a.icon-ok").click()}).first().keyup().focus();$("#fenetre a.icon-ok").on("click",function(){insert(el,'<a href="'+$("#url").val()+'">',"</a>",$("#texte").val());$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_tex(el){var chargement=typeof MathJax=="undefined"?'<script type="text/javascript" src="/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script type="text/x-mathjax-config">MathJax.Hub.Config({tex2jax:{inlineMath:[["$","$"],["\\\\(","\\\\)"]]}});</script>':"";var sel=marqueselection(el);var type="t1";if(sel.length)switch(sel.substring(0,2)){case"\\[":case"$$":type="t2";case"\\(":sel=sel.substring(2,sel.length-2);break;default:sel=sel.trim("$")}popup(chargement+'<a class="icon-montre" title="Mettre à jour l\'aperçu"></a><a class="icon-ok" title="Valider"></a><h3>Insertion de formules LaTeX</h3>  <p>Vous pouvez ci-dessous entrer et modifier une formule LaTeX. L\'aperçu présent en bas sera mis à jour uniquement lorsque vous cliquez sur l\'icône <span class="icon-montre"></span>.</p>  <p class="ligne"><label for="t1">La formule est en ligne (pas de retour)</label><input type="radio" name="type" id="t1" value="1"></p>  <p class="ligne"><label for="t2">La formule est hors ligne (formule centrée)</label><input type="radio" name="type" id="t2" value="2"></p>  <textarea id="formule" rows="3">'+sel+'</textarea>  <hr><h3>Aperçu</h3><div id="apercu" style="text-align:center;">[Demandez l\'aperçu en cliquant sur l\'icône <span class="icon-montre"></span>]</div>',true);$("#"+type).prop("checked",true);$("#formule").focus();$("#fenetre a.icon-montre").on("click",function(){if($("#formule").val().length){$("#apercu").html($("#t1").is(":checked")?"$"+$("#formule").val()+"$":"\\["+$("#formule").val()+"\\]").css("text-align","left");MathJax.Hub.Queue(["Typeset",MathJax.Hub,"apercu"])}else $("#apercu").html("[Écrivez une formule]").css("text-align","center")});$("#fenetre a.icon-ok").on("click",function(){if($("#t1").is(":checked"))insert(el,"$","$",$("#formule").val());else insert(el,"\\[","\\]",$("#formule").val());$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_par1(el){insert(el,"<p>","</p>")}function insertion_par2(el){insert(el,"<div class='note'>","</div>")}function insertion_par3(el){insert(el,"<div class='annonce'>","</div>")}function insertion_retour(el){insert(el,"<br>","")}function insertion_gras(el){insert(el,"<strong>","</strong>")}function insertion_italique(el){insert(el,"<em>","</em>")}function insertion_souligne(el){insert(el,"<u>","</u>")}function insertion_exp(el){insert(el,"<sup>","</sup>")}function insertion_ind(el){insert(el,"<sub>","</sub>")}function aidetexte(){popup('<h3>Aide et explications</h3>  <p>Il y a deux modes d\'éditions possibles pour éditer un texte&nbsp;: le mode «&nbsp;balises visibles&nbsp;» et le mode «&nbsp;balises invisibles&nbsp;». Il est possible de passer de l\'un à l\'autre&nbsp;:</p>  <ul>    <li><span class="icon-source"></span> permet de passer en mode «&nbsp;balises visibles&nbsp;» (par défaut), où le texte à taper est le code HTML de l\'article. Ce mode est plus précis. Les boutons aux dessus aident à utiliser les bonnes balises.</li>    <li><span class="icon-nosource"></span> permet de passer en mode «&nbsp;balises invisibles&nbsp;», où le texte est tel qu\'il sera affiché sur la partie publique, et modifiable. Ce mode est moins précis, mais permet le copié-collé depuis une page web ou un document Word/LibreOffice.  </ul>  <p>Une fonction de nettoyage du code HTML, permettant d\'assurer une homogénéité et une qualité d\'affichage optimales, est lancée à chaque commutation entre les deux modes, à chaque clic sur un des boutons disponibles, à chaque copie/coupe de texte et à chaque passage à la ligne.</p>  <p>En HTML, toutes les mises en formes sont réalisées par un encadrement de texte entre deux balises&nbsp;: &lt;h3&gt; et &lt;/h3&gt; pour un gros titre, &lt;p&gt; et &lt;/p&gt; pour un paragraphe. Le retour à la ligne simple, qui ne doit exister que très rarement, est une balise simple &lt;br&gt;. Mais les boutons disponibles sont là pour vous permettre de réaliser le formattage que vous souhaitez&nbsp;:</p>  <ul>    <li><span class="icon-titres"></span>&nbsp;: différentes tailles de titres (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-par1"></span>&nbsp;: paragraphe classique, qui doit obligatoirement encadrer au minimum chaque ligne de texte. Apparaît automatiquement au passage à la ligne si on l\'oublie.</li>    <li><span class="icon-par2"></span>&nbsp;: paragraphe important, écrit en rouge</li>    <li><span class="icon-par3"></span>&nbsp;: paragraphe très important, écrit en rouge et encadré</li>    <li><span class="icon-retour"></span>&nbsp;: retour à la ligne. Identique à un appui sur Entrée, et souvent inutile.</li>    <li><span class="icon-gras"></span>&nbsp;: mise en gras du texte entre les balises</li>    <li><span class="icon-italique"></span>&nbsp;: mise en italique du texte entre les balises</li>    <li><span class="icon-souligne"></span>&nbsp;: soulignement du texte entre les balises</li>    <li><span class="icon-omega"></span>&nbsp;: lettres grecques (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-sigma"></span>&nbsp;: symboles mathématiques (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-exp"></span>&nbsp;: mise en exposant du texte entre les balises</li>    <li><span class="icon-ind"></span>&nbsp;: mise en indice du texte entre les balises</li>    <li><span class="icon-ol"></span>&nbsp;: liste numérotée. Une fenêtre supplémentaire permet de choisir le type (1,A,a,I,i) et la première valeur. Les différentes lignes de la liste sont constituées par les balises &lt;li&gt; et &lt;/li&gt;</li>    <li><span class="icon-ul"></span>&nbsp;: liste à puces. Les différentes lignes de la liste sont constituées par les balises &lt;li&gt; et &lt;/li&gt;</li>    <li><span class="icon-lien1"></span>&nbsp;: lien d\'un document disponible ici (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-lien2"></span>&nbsp;: lien vers un autre site web (fenêtre supplémentaire pour entre l\'adresse)</li>    <li><span class="icon-tex"></span>&nbsp;: insertion de code LaTeX (fenêtre supplémentaire pour le taper)</li>  </ul>  <p class="tex2jax_ignore">Il est possible d\'insérer du code en LaTeX, sur une ligne séparée (balises \\[...\\] ou balises $$...$$) ou au sein d\'une phrase (balises $...$ ou balises \\(...\\)). Il faut ensuite taper du code en LaTeX à l\'intérieur. La prévisualisation est réalisée en direct.</p>',false)
-}function echange(el1,el2){if(el1.length&&el2.length){$("article").css("position","relative");el1.css("opacity",.3);el2.css("opacity",.3);el2.animate({top:el1.position().top-el2.position().top},1e3);el1.animate({top:(el2.outerHeight(true)+el2.outerHeight())/2},1e3,function(){el1.css("opacity",1);el2.css("opacity",1);el1.insertAfter(el2);el1.css({position:"static",top:0});el2.css({position:"static",top:0})})}}function cache(el){var prop=el.parent().attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{cache:1,action:prop[0],id:prop[1]},dataType:"json",el:el,fonction:function(el){el.parent().addClass("cache");el.removeClass("icon-cache").addClass("icon-montre").off("click").on("click",function(){montre($(this))}).attr("title","Montrer à nouveau")}})}function montre(el){var prop=el.parent().attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{montre:1,action:prop[0],id:prop[1]},dataType:"json",el:el,fonction:function(el){el.parent().removeClass("cache");el.removeClass("icon-montre").addClass("icon-cache").off("click").on("click",function(){cache($(this))}).attr("title","Cacher à nouveau")}})}function monte(el){var parent=el.parent();var prop=parent.attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{monte:1,action:prop[0],id:prop[1]},dataType:"json",el:parent,fonction:function(el){if(!el.prev().prev().is("article")){el.children(".icon-monte").hide(1e3);el.prev().children(".icon-monte").show(1e3)}if(!el.next().is("article")){el.children(".icon-descend").show(1e3);el.prev().children(".icon-descend").hide(1e3)}echange(el.prev(),el)}})}function descend(el){var parent=el.parent();var prop=parent.attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{descend:1,action:prop[0],id:prop[1]},dataType:"json",el:parent,fonction:function(el){if(!el.prev().is("article")){el.children(".icon-monte").show(1e3);el.next().children(".icon-monte").hide(1e3)}if(!el.next().next().is("article")){el.children(".icon-descend").hide(1e3);el.next().children(".icon-descend").show(1e3)}echange(el,el.next())}})}function supprime(el){var parent=el.parent();var prop=parent.data("id").split("|");var item="un élément";switch(prop[0]){case"infos":item="une information";break;case"pages":item="la matière <em>"+$("h3",parent).text()+"</em>. Les informations qui y sont écrites seront aussi supprimées";break;case"reps":item="le répertoire <em>"+$(".nom",parent).map(function(){return this.textContent||$(this).find("input").val()}).get(0)+"</em>. <strong>Tous les sous-répertoires et documents qui s'y trouvent seront aussi supprimés</strong>";break;case"docs":item="le document <em>"+$(".nom",parent).map(function(){return this.textContent||$(this).find("input").val()}).get(0)+"</em>";break;case"colles":item="le programme de colle de la "+$(".edition",parent).text().toLowerCase();break;case"cdt-elems":item="un élément du cahier de texte";break;case"cdt-types":item="le type de séances <em>"+$("h3",parent).text()+"</em>. <strong>Les éléments du cahier de texte associés à ce type seront aussi supprimés</strong>";break;case"cdt-raccourcis":item="le raccourci de séance <em>"+$("h3",parent).text()+"</em>. Aucun élément du cahier de texte ne sera supprimé";break;case"notes":parent=parent.parent();item="une colle ou séance sans note du <em>"+$("td:first",parent).text()+"</em>, d'une durée de "+$("td:eq(3)",parent).text()+". Toutes les notes de cette colle seront supprimées";break;case"matieres":item="la matière <em>"+$("h3",parent).text()+"</em>. <p class=\"note\"><strong>ATTENTION&nbsp;: Les programmes de colles, le cahier de texte et les notes correspondantes seront toutes automatiquement supprimées.</strong></p> <p>Les répertoires, les documents, les pages d'informations spécifiques et les éléments de l'agenda associés à la matière seront conservés mais ne seront plus associés à une matière&nbsp;: ils seront désormais visibles dans le contexte «&nbsp;général&nbsp;».<br><strong>Si vous souhaitez simplement réinitialiser la matière, ce n'est pas la bonne méthode</strong>&nbsp;: vous devriez pouvoir faire ce que vous souhaitez avec les possibilités de cette page";break;case"groupes":item="le groupe <em>"+($(".editable",parent).text()||$("input:first",parent).val())+"</em>. Les utilisateurs concernés ne seront pas supprimés";break;case"agenda-elems":item="un événement de l'agenda";break;case"agenda-types":item="le type d'événement <em>"+$("h3",parent).text()+"</em>. <strong>Les événements de l'agenda associés à ce type seront aussi supprimés</strong>";break}confirmation("Vous allez supprimer XXX.<br>Cette opération n'est pas annulable.".replace("XXX",item),this,function(el){$.ajax({url:"ajax.php",method:"post",data:{supprime:1,action:prop[0],id:prop[1]},dataType:"json",el:parent,fonction:function(el){if(prop[0].match(/^(agenda|colles)$/))location.reload(true);else el.remove()}})})}function lock(el){var parent=el.parent();var prop=parent.data("id").split("|");var protection=el.data("val");popup('<a class="icon-ok" title="Valider ce choix"></a><h3>Accès à l\'information</h3><table id="selmult">  <tr class="categorie"><td>Accès public</td><td><input value="0" type="checkbox"></td></tr>  <tr class="categorie"><td>Utilisateurs identifiés</td><td><input value="6" type="checkbox"></td></tr>  <tr class="element"><td>Invités</td><td><input value="1" type="checkbox"></td></tr>  <tr class="element"><td>Élèves</td><td><input value="2" type="checkbox"></td></tr>  <tr class="element"><td>Colleurs</td><td><input value="3" type="checkbox"></td></tr>  <tr class="element"><td>Administratifs</td><td><input value="4" type="checkbox"></td></tr>  <tr class="element"><td>Professeurs</td><td><input value="5" type="checkbox"></td></tr>  <tr class="categorie"><td>Information invisible</td><td><input value="32" type="checkbox"></td></tr>  </tbody></table>',true);var f=$("#fenetre");if(protection==0||protection==32)$('input[value="'+protection+'"]',f).prop("checked",true).change();else{$("input[value=6]",f).prop("checked",true).change();for(var a=1;a<6;a++)if((protection-1>>a-1&1)==0)$('input[value="'+a+'"]',f).prop("checked",true).change()}var f=$("#fenetre");$("input[value=0],input[value=6],input[value=32]",f).parent().parent().addClass("categorie");$("tr:not(.categorie)",f).addClass("element");$("input",f).on("click",function(){if(this.value==0||this.value==32)$(this).parent().parent().siblings().find("input[type=checkbox]").prop("checked",false).change();else{$("input[value=0],input[value=32]",f).prop("checked",false).change();$("input[value=6]",f).prop("checked",true).change();if(this.value==6)$("tr:not(.categorie) input",f).prop("checked",true).change()}});$("tr",f).on("click",function(e){if(!$(e.target).is("input"))$(this).find("input").click()});$("input",f).on("change",function(){$(this).parent().parent().removeClass("sel");if(this.checked)$(this).parent().parent().addClass("sel")});$(".icon-ok",f).on("click",function(){if($('input[value="32"]',f).prop("checked"))var val=32;else if($('input[value="0"]',f).prop("checked"))var val=0;else var val=32-$("input:checked:not([value=6])",f).map(function(){return this.value|0}).get().reduce(function(acc,v){return acc+Math.pow(2,v-1)},0);el.data("val",val);$.ajax({url:"ajax.php",method:"post",data:{action:prop[0],id:prop[1],champ:"protection",val:val},dataType:"json",el:parent,fonction:function(el){location.reload(true)}})})}function ajoutecolle(el){var article=el.parent();el.before('<a class="icon-annule" title="Annuler"></a><a class="icon-ok" title="Valider"></a>');el.next().addBack().hide();var form=$("<form></form>").appendTo(article).html($("#form-ajoutecolle").html());$("textarea",form).textareahtml();$("input",form).attr("id","cache");$(".icon-annule",article).on("click",function(){$("form,.icon-annule,.icon-ok",article).remove();el.next().addBack().show()});$("a.icon-ok",article).on("click",function(){$("textarea",form).each(function(){this.value=nettoie($(this).is(":visible")?this.value:$(this).next().html())});var id=article.data("id").split("|")[1];$.ajax({url:"ajax.php",method:"post",data:form.serialize()+"&action=ajout-colle&id="+id,dataType:"json",el:article,fonction:function(el){var texte=$("textarea",el).val();var cache=$("input",el).is(":checked");if(cache)el.addClass("cache");el.data("id","colles|"+id);$(".icon-aide",el).nextAll().remove();$(".icon-aide",el).after((cache?'<a class="icon-montre" title="Afficher le programme de colles sur la partie publique"></a>':'<a class="icon-cache" title="Rendre invisible le programme de colles sur la partie publique"></a>')+'<a class="icon-supprime" title="Supprimer ce programme de colles"></a><div class="editable edithtml" data-id="colles|texte|'+id+'" placeholder="Texte du programme de colles">'+texte+"</div>");$("a.icon-cache,a.icon-montre,a.icon-supprime",el).on("click",function(){window[this.className.substring(5)]($(this))});$(".editable",el).editinplace()}})});$("input,select",form).on("keypress",function(e){if(e.which==13){e.preventDefault();$("a.icon-ok",article).click()}})}function valide(){var data="";if($("#planning").length)data="action=planning&"+$("form").serialize();else{var id=$(this).parent().attr("data-id").split("|");data="action="+id[0]+"&id="+id[1]+"&"+$(this).nextAll("form").serialize()}if(data.length)$.ajax({url:"ajax.php",method:"post",data:data,dataType:"json",el:this,fonction:function(el){if(el.classList[1]!="noreload")location.reload(true)}});else affiche("<p>Aucune donnée envoyée.</p>","nok")}function formulaire(){var idform=this.className.split(" ")[0].substring(5);var action=$("#form-"+idform).data("action");$("#epingle").remove();var article=$('<article id="epingle"><a class="icon-ferme" title="Fermer"></a>  <a class="icon-aide" title="Aide pour ce formulaire"></a>  <a class="icon-ok" title="Valider"></a></article>').insertBefore($("article,#calendrier,#parentsdoc+*").first());var form=$("<form></form>").appendTo(article).html($("#form-"+idform).html());$(".edithtml",form).textareahtml();$("input[name], select[name]:not([multiple])",form).attr("id",function(){return this.getAttribute("name")});switch(action){case"reps":$(this).init_reps();break;case"ajout-rep":form.append('<input type="hidden" name="parent" value="'+$(this).parent().data("id").split("|")[1]+'">');break;case"docs":case"ajout-doc":$(this).init_docs(action);break;case"cdt-elems":form.init_cdt_boutons();break;case"ajout-cdt-raccourci":form.init_cdt_raccourcis();break;case"notes":case"ajout-notes":$(this).init_notes(action);break;case"agenda-elems":$(this).init_evenements();break;case"ajout-agenda-types":$('[name="couleur"]',form).colpick();break;case"deplcolle":$("#ancien,#nouveau").each(function(){$(this).datetimepicker({format:"d/m/Y Ghi",timepicker:true})});break;case"ajout-utilisateurs":form.init_ajout_utilisateurs();break;case"ajout-groupe":$(".usergrp span",form).on("click",utilisateursgroupe);break}$("select[multiple]",form).each(selmult);$("#epingle .icon-ferme").on("click",function(){$("#epingle").remove()});$("#epingle a.icon-aide").on("click",function(){popup($("#aide-"+idform).html(),false)});$("#epingle a.icon-ok").on("click",function(){$(".edithtml",form).each(function(){this.value=nettoie($(this).is(":visible")?this.value:$(this).next().html())});if(action=="notes"||action=="ajout-notes")$("#epingle select:not(:visible)").val("x");$.ajax({url:"ajax.php",method:"post",data:form.serialize()+"&action="+action,dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$("input,select",form).on("keypress",function(e){if(e.which==13){e.preventDefault();$("#epingle a.icon-ok").click()}})}$.fn.init_reps=function(){var el=$(this);var form=$("#epingle form");var sel=$("select[multiple]",form);var id=el.parent().data("id").split("|")[1];var donnees=el.parent().data("donnees").split("|");var protection=donnees[2];var nom=el.siblings(".nom").text().split(/\/\s/).pop()||el.parent().find("input").val();$("em",form).text(nom);if(protection==0||protection==32)sel.val(protection);else{sel.val(6);for(var a=1;a<6;a++)if((protection-1>>a-1&1)==0)$('option[value="'+a+'"]',sel).prop("selected",true)}if(donnees[0]==0)$("#nom,#parent,#menu",form).parent().remove();else{$("#nom",form).val(nom);if(donnees[1]=="1")$("#menu",form).prop("checked",true);$('[data-parents*=",'+id+',"]',form).prop("disabled",true)}form.append('<input type="hidden" name="id" value="'+id+'">');$('input[type="button"]',form).on("click",function(){var action=this.value.substring(0,4)=="Prop"?"propage":"vide";var contexte=$(this).parent().find("em").text();var texte=action=="propage"?"Vous allez propager le réglage d'accès du répertoire <em>"+contexte+"</em> à l'ensemble de ses sous-répertoires et des documents qu'ils contiennent.<br>Vous pourrez modifier à nouveau le réglage de chaque document ou répertoire, de façon individuelle.":"Vous allez vider le répertoire <em>"+contexte+"</em>. Cela supprimera définitivement l'ensemble de ses sous-répertoires et des documents qu'ils contiennent.<br>Cette opération n'est pas annulable.";confirmation(texte,this,function(el){$.ajax({url:"ajax.php",method:"post",data:"action=reps&id="+id+"&"+action+"=1",dataType:"json",el:"",fonction:function(el){location.reload(true)}})})})};$.fn.init_docs=function(action){var el=$(this);var form=$("#epingle form");var nom=el.siblings(".nom").text().split(/\/\s/).pop()||el.parent().find("input").val();$("em",form).text(nom);var id=el.parent().data("id").split("|")[1];if(action=="docs"){var protection=el.parent().data("protection");form.append('<input type="hidden" name="id" value="'+id+'">');$("#nom",form).val(nom)}else{var protection=el.parent().data("donnees").split("|")[2];$("#fichier",form).on("change",function(){if(!$("#nom",form).val().length){var f=this.value;$("#nom",form).val(f.substring(f.lastIndexOf("\\")+1,f.lastIndexOf("."))||f)}});form.append('<input type="hidden" name="parent" value="'+id+'">')}var sel=$("select[multiple]",form);if(protection==0||protection==32)sel.val(protection);else{sel.val(6);for(var a=1;a<6;a++)if((protection-1>>a-1&1)==0)$('option[value="'+a+'"]',sel).prop("selected",true)}form.append('<input type="hidden" name="action" value="'+action+'">');$("#epingle a.icon-ok").addClass("icon-envoidoc").removeClass("icon-ok").on("click",function(){$.ajax({url:"docs.php",method:"post",data:"connexion=1",dataType:"json",el:"",fonction:function(el){if($("#fichier")[0].files.length>0){window.clearTimeout(extinction);$("#log").html("Envoi du document. Cela peut prendre du temps...")}var data=new FormData(form[0]);$.ajax({url:"ajax.php",method:"post",data:data,dataType:"json",contentType:false,processData:false,el:"",fonction:function(el){location.reload(true)}})}})})};$.fn.init_cdt_boutons=function(){var form=this;$("#jour,#pour").datetimepicker({format:"d/m/Y",timepicker:false});$("#h_debut").datetimepicker({format:"Ghi",datepicker:false,onClose:function(t,input){$("#h_fin").val(function(i,v){return v||(input.val().length?parseInt(input.val().slice(0,-3))+2+input.val().slice(-3):"")})}});$("#h_fin").datetimepicker({format:"Ghi",datepicker:false});var zero=function(n){return String(n).length==1?"0"+n:String(n)};$("#raccourci").on("change keyup",function(){var valeurs=raccourcis[this.value];for(var cle in valeurs){if(cle=="jour"){var t=new Date;var j=parseInt(valeurs["jour"]);t.setDate(j>t.getDay()?t.getDate()-t.getDay()-7+j:t.getDate()-t.getDay()+j);$("#jour").val(zero(t.getDate())+"/"+zero(t.getMonth()+1)+"/"+t.getFullYear())}else $("#"+cle).val(valeurs[cle])}$(this).data("modif",1);$("#tid").change()}).data("modif",0);$("#tid").on("change keyup",function(){switch(parseInt(seances[this.value])){case 0:$("#h_debut,#demigroupe").parent().show();$("#h_fin,#pour").parent().hide();break;case 1:$("#h_debut,#h_fin,#demigroupe").parent().show();$("#pour").parent().hide();break;case 2:$("#h_debut,#h_fin").parent().hide();$("#pour,#demigroupe").parent().show();break;case 3:$("#h_debut,#h_fin,#pour").parent().hide();$("#demigroupe").parent().show();break;default:$("#h_debut,#h_fin,#pour,#demigroupe").parent().hide()}$("#jour").change()});$("input,#demigroupe",form).on("change keyup",function(){if($("#raccourci").data("modif")==0)$("#raccourci").val(0);else $("#raccourci").data("modif",0)});$("input,select",form).on("keypress",function(e){if(e.which==13)$("a.icon-ok",el).click()});$("select:first",form).focus();$("#tid").change()};$.fn.init_cdt_raccourcis=function(){this.each(function(){var form=$(this);$('[id^="h_d"]',form).datetimepicker({format:"Ghi",datepicker:false,onClose:function(t,input){$('[id^="h_f"]',form).val(function(i,v){return v||(input.val().length?parseInt(input.val().slice(0,-3))+2+input.val().slice(-3):"")})}});$('[id^="h_fin"]').datetimepicker({format:"Ghi",datepicker:false});$('[id^="type"]',form).on("change keyup",function(){switch(parseInt(seances[this.value])){case 0:$('[id^="h_d"],[id^="dem"]',form).parent().show();$('[id^="h_f"]',form).parent().hide();break;case 1:$('[id^="h_d"],[id^="h_f"],[id^="dem"]',form).parent().show();break;case 2:case 3:$('[id^="h_d"],[id^="h_f"]',form).parent().hide();$('[id^="dem"]',form).parent().show();break;default:$('[id^="h_d"],[id^="h_f"],[id^="dem"]',form).parent().hide()}}).change();$("input,select",form).on("keypress",function(e){if(e.which==13)$("a.icon-ok",form).click()})})};$.fn.init_notes=function(action){var el=$(this);var form=$("#epingle form").append($("#form-notes").html());var table=$("table",form);$("input, select",form).attr("id",function(){return this.getAttribute("name")});$("tr[data-id]",table).append("<td>"+$("div",form).html()+"</td>");$("select",table).attr("name",function(){return"e"+$(this).parent().parent().data("id")});$("div",form).remove();if($("input:checkbox",table).length){$("tr[data-id]",form).hide();$("input:checkbox",table).on("change",function(){if($("input:checkbox:last",table).prop("checked"))return $("tr[data-id]",form).show();var ids=$("input:checked",table).map(function(){return this.value.split(",")}).get().concat();$("tr[data-id]:not(.orig)",table).hide();for(var i=0;i<ids.length;i++)$('tr[data-id="'+ids[i]+'"]',form).show()})}function marque_dejanotes(sid){if(sid==0)return true;var dn=dejanotesautres[sid].split(",");for(var i=0;i<dn.length;i++)$('tr[data-id="'+dn[i]+'"]',form).addClass("dejanote").find("td:eq(0)").text(function(){return this.textContent+" (noté par un autre colleur)"});var dn=dejanotesperso[sid].split(",");for(var i=0;i<dn.length;i++)$('tr[data-id="'+dn[i]+'"]:not(.orig)',form).addClass("dejanote").find("td:eq(0)").text(function(){return this.textContent+" (déjà noté par vous-même)"});$(".dejanote select").prop("disabled",true).val("x")}$("#jour").datetimepicker({format:"d/m/Y",timepicker:false,onShow:function(){if($("#td").is(":checked"))this.setOptions({minDate:$("#form-ajoute option:eq(1)").data("date"),maxDate:new Date(new Date($("#form-ajoute option:last").data("date").replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x})).getTime()+6*864e5)});else this.setOptions({minDate:debut||$("#sid option:selected").data("date"),maxDate:new Date(new Date((fin||$("#sid option:selected").next().data("date")).replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x})).getTime()-864e5)})}});$("#heure").datetimepicker({format:"Ghi",datepicker:false,defaultTime:"15h30"});$("#duree").datetimepicker({format:"Ghi",datepicker:false,defaultTime:"0h00",step:10}).on("change",function(){$(this).removeClass("auto")});$("select",table).on("change keyup",function(){var nb=$("table select:visible",form).filter(function(){return this.value!="x"}).length;var duree=nb*(dureecolle||20);if($("#duree").is(".auto")||duree>$("#duree").val().replace(/^(\d*)h(\d*)$/,function(tout,x,y){return 60*(x|0)+(y|0)}))$("#duree").val((duree/60|0)+"h"+(duree%60||"")).addClass("auto")});if(action=="ajout-notes"){$("#sid").on("change keyup",function(){$(".dejanote td:first-child").text(function(){return this.textContent.replace(" (noté par un autre colleur)","").replace(" (déjà noté par vous-même)","")});$(".dejanote").removeClass("dejanote").find("select").prop("disabled",false);marque_dejanotes($("#sid").val());var jour=new Date($("#jour").val().replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));var debut=new Date($("#sid option:selected").data("date").replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));var fin=new Date($("#sid option:selected").next().data("date").replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));if(jour<debut||jour>fin){debut=debut.toJSON();$("#jour").val(debut.substr(8,2)+"/"+debut.substr(5,2)+"/"+debut.substr(0,4))}}).change();$("#td").on("change keyup",function(){if(this.checked){$("#sid").parent().hide();$("#description").parent().show();table.hide()}else{$("#sid").parent().show();$("#description").parent().hide();table.show()}});$("#description").parent().hide()}else{var tr=el.parent().parent();if(el.data("sid")){$("#description, #td").parent().remove();var sid=el.data("sid");var debut=$('#form-ajoute option[value="'+sid+'"]').data("date");var fin=$('#form-ajoute option[value="'+sid+'"]').next().data("date");var eleves=el.data("eleves").split("|");var notes=el.data("notes").split("|");for(var i=0;i<eleves.length;i++)$('tr[data-id="'+eleves[i]+'"]',form).addClass("orig").show().find("select").val(notes[i]).on("change",function(){$(this).parent().parent().removeClass("orig")});$("h3",form).text("Modifier des notes - semaine du "+$('select[name="sid"] option[value="'+sid+'"]').text().split(" ").slice(0,3).join(" "));if(el.next().length)marque_dejanotes(sid);else{$('tr:not(.orig), .orig option[value="x"]',table).remove();$("#duree").prop("disabled",true);form.append("<p>Cette colle a déjà été relevée&nbsp;: il est impossible de modifier quels élèves ont été interrogés ou la durée de la colle. Vous pouvez corriger la date et l'heure (dans la limite de la semaine enregistrée) ou les notes que vous avez mises vous pouvez mettre une note à un élève initialement absent qui a rattrapé sa colle.</p>")}}else{table.remove();$("#td").prop("checked",true).prop("disabled",true);$("#description").val(el.parent().prev().prev().prev().text());$("h3",form).text("Modifier la séance de TD sans note");if(el.next().length==0){$("#duree").prop("disabled",true);form.append("<p>Cette séance a déjà été relevée&nbsp;: il est impossible de modifier sa durée. Vous pouvez corriger la date, l'heure ou la description.</p>")}}$("#id").val(el.parent().data("id").split("|")[1]);$("#jour").val($("td:eq(0)",tr).text().replace(/(.{6})(.{2})/,function(tout,x,y){return x+"20"+y}));$("#heure").val($("td:eq(1)",tr).text().replace("-",""));$("#duree").val($("td:eq(3)",tr).text())}};$.fn.init_ajout_utilisateurs=function(){$("#autorisation,#saisie").on("change",function(){var f=$("#epingle form");var a=$("#autorisation",f).val();if(a==0){$(".affichesiinvite,.affichesiinvitation,.affichesimotdepasse,.mailenvoi,.mailliste",f).hide(0);$("textarea",f).prop("disabled",true).attr("placeholder","Zone de saisie des utilisateurs\nSélectionnez d'abord un type d'utilisateur")}else{var inv=a==1;var mdp=$("#saisie",f).val()==2;$("#saisie",f).parent().toggle(!inv);$(".affichesiinvite",f).toggle(inv);$(".affichesiinvitation",f).toggle(!inv&&!mdp);$(".affichesimotdepasse",f).toggle(!inv&&mdp);$(".mailenvoi",f).toggle(!inv);$(".mailliste",f).toggle(a>2);$("#mailenvoi",f).prop("disabled",mdp).change();$("textarea",f).prop("disabled",false).attr("placeholder",function(){if(inv)return"identifiant_1,motdepasse_1\nidentifiant_2,motdepasse_2\nidentifiant_3,motdepasse_3\n...";else if(mdp)return"nom_1,prénom_1,motdepasse_1\nnom_2,prénom_2,motdepasse_2\nnom_3,prénom_3,motdepasse_3\n...";else return"nom_1,prénom_1,adresse_1\nnom_2,prénom_2,adresse_2\nnom_3,prénom_3,adresse_3\n..."})}}).change();$("#epingle #mailenvoi").on("change",function(){$("#epingle #mailliste").attr("disabled",!this.checked||this.disabled)}).change()};$.fn.init_evenements=function(){var el=$(this);var form=$("#epingle form");$("textarea",form).attr("id","texte");if(el.is(".modifevnmt")){var id=el.attr("id").substr(1);var valeurs=evenements[id];var cles=["type","matiere","debut","fin","texte"];for(var i=0;i<6;i++){$("#"+cles[i]).val(valeurs[cles[i]])}$("#id").val(id);$("#texte").change();$("#jours").prop("checked",valeurs["je"]);$('<a class="icon-supprime" title="Supprimer cette information"></a>').insertBefore($(".icon-ok")).on("click",function(){supprime($(this))}).parent().data("id","agenda-elems|"+id)}$("#debut").datetimepicker({onShow:function(){this.setOptions({maxDate:$("#fin").val()||false})},onClose:function(t,input){$("#fin").val(function(i,v){return v||input.val()})}});$("#fin").datetimepicker({onShow:function(){this.setOptions({minDate:$("#debut").val()||false})},onClose:function(t,input){$("#debut").val(function(i,v){return v||input.val()})}});$("#jours").on("change",function(){var v;if(this.checked){$("#debut,#fin").each(function(){v=this.value.split(" ");$(this).val(v[0]).attr("data-heure",v[1]).datetimepicker({format:"d/m/Y",timepicker:false})})}else{$("#debut,#fin").each(function(){if(this.hasAttribute("data-heure"))$(this).val(this.value+" "+$(this).attr("data-heure")).removeAttr("data-heure");$(this).datetimepicker({format:"d/m/Y Ghi",timepicker:true})})}}).change()};function selmult(){var sel=$(this);var isacces=this.getAttribute("name").indexOf("protection")+1?1:0;function majselect(sel){sel.prev().children().prop("selected",false).text(function(){var options=$(isacces?"option:selected:not([value=6])":"option:selected",sel);if(isacces&&options.length==5)return"Tout utilisateur identifié";if(options.length==0)return"Choisir ...";else return options.map(function(){return this.textContent}).get().join(", ")}).prop("selected",true)}$("<select id="+sel.prev().attr("for")+"><option selected hidden></option></select>").insertBefore(sel.hide(0)).attr("disabled",sel.attr("disabled")).on("mousedown",function(e){e.preventDefault();this.blur();popup('<a class="icon-ok" title="Valider ce choix"></a><h3>'+sel.prev().prev().text().replace(":","")+'</h3><table id="selmult">'+$("option",sel).map(function(){return"<tr"+(this.selected?' class="sel"':"")+"><td>"+this.textContent+'</td><td><input type="checkbox" '+(this.selected?"checked ":"")+'value="'+this.value+'"></td></tr>'}).get().join("")+"</table>",true);var f=$("#fenetre");if(isacces){$("input[value=0],input[value=6],input[value=32]",f).parent().parent().addClass("categorie");$("tr:not(.categorie)",f).addClass("element");$("input",f).on("click",function(){if(this.value==0||this.value==32)$(this).parent().parent().siblings().find("input[type=checkbox]").prop("checked",false).change();else{$("input[value=0],input[value=32]",f).prop("checked",false).change();$("input[value=6]",f).prop("checked",true).change();if(this.value==6)$("tr:not(.categorie) input",f).prop("checked",true).change()}})}else{$("#selmult",f).prepend('<tr class="categorie"><th></th><th><a class="icon-cocher"></a></th></tr>');$(".icon-cocher",f).on("click",cocher_utilisateurs)}$("tr",f).on("click",function(e){if(!$(e.target).is("input"))$(this).find("input").click()});$("input",f).on("change",function(){$(this).parent().parent().removeClass("sel");if(this.checked)$(this).parent().parent().addClass("sel")});$(".icon-ok",f).on("click",function(){sel.val($("input:checked",f).map(function(){return this.value}).get());majselect(sel);$("#fenetre, #fenetre_fond").remove()})});majselect(sel)}function cocher_utilisateurs(){$(this).toggleClass("icon-cocher icon-decocher").parent().parent().nextUntil(".categorie").find("input").prop("checked",$(this).hasClass("icon-decocher")).change()}function init_utilisateurs(){$(".icones.mailenvoi").each(function(){this.innerHTML=this.textContent==1?'<a class="icon-ok" title="Supprimer la possibilité d\'envoyer des courriels"></a>':'<a class="icon-nok" title="Accorder la possibilité d\'envoyer des courriels"></a>'});$(".mailenvoi a").on("click",mail_utilisateur);$("th .icon-mail").on("click",mail_utilisateurs);$(".icon-cocher").on("click",cocher_utilisateurs);$("td .icon-edite").on("click",edite_utilisateur);$("td .icon-desactive, td .icon-active, td .icon-supprutilisateur, td .icon-validutilisateur").on("click",modif_utilisateur);$("th .icon-desactive, th .icon-active, th .icon-supprutilisateur, th .icon-validutilisateur").on("click",modif_utilisateurs);$("td:not(.icones)").on("click",function(e){$(this).parent().find("input").click()});$("#utilisateurs input").on("change",function(){$(this).parent().parent().removeClass("sel");if(this.checked)$(this).parent().parent().addClass("sel")});function mail_utilisateur(){var val=$(this).hasClass("icon-ok");$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateur",modif:"mailenvoi",id:$(this).parent().parent().data("id"),val:1-val},dataType:"json",el:$(this),fonction:function(el){el.toggleClass("icon-ok icon-nok").attr("title",(val?"Accorder":"Supprimer")+" la possibilité d'envoyer des courriels")}})}function edite_utilisateur(){var id=$(this).parent().parent().data("id");$.ajax({url:"recup.php",method:"post",data:{action:"prefs",id:id},dataType:"json",afficheform:function(data){if("nom"in data){popup($("#form-edite").html(),true);var f=$("#fenetre");$("input[name]",f).attr("id",function(){return this.getAttribute("name")});if(data["valide"])$("#comptedesactive, #demande, #invitation",f).remove();else if(data["demande"])$("#compteactif, #comptedesactive, #invitation",f).remove();else if(data["invitation"])$("#compteactif, #comptedesactive, #demande",f).remove();else $("#compteactif, #demande, #invitation",f).remove();if(data["autorisation"]==2)$("#mailliste",f).parent().remove();else if(data["autorisation"]==1)$("#mailenvoi, #mailexp, #mailcopie, #mailliste",f).parent().remove();$("p:first",f).html(function(i,code){return code.replace("XXX",data["prenom"].length?"de <em>"+data["prenom"]+" "+data["nom"]+"</em>":"<em>"+data["login"]+"</em>").replace("YYY","<em>"+["Invité","Élève","Colleur","Administratif","Professeur"][data["autorisation"]-1]+"</em>")});$('input[type="text"],input[type="email"]',f).val(function(){return data[this.id]});$('input[type="checkbox"]',f).prop("checked",function(){return data[this.id]});$("#mailenvoi",f).on("click",function(){$("#mailexp, #mailcopie, #mailliste",f).prop("disabled",!this.checked);if(this.checked&&!$("#mailexp",f).val())$("#mailexp",f).val(data["prenom"]+" "+data["nom"])});$("#mailexp, #mailcopie, #mailliste",f).prop("disabled",!$("#mailenvoi",f).prop("checked"));$("a.icon-ok",f).on("click",function(){$.ajax({url:"ajax.php",method:"post",data:"action=utilisateur&modif=prefs&id="+id+"&"+$("form",f).serialize(),dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$("input",f).on("keypress",function(e){if(e.which==13){e.preventDefault();$("a.icon-ok",f).click()}})}}})}function modif_utilisateur(){var question="";var compte=$(this).parent().siblings().first().text();compte=compte.length?"de <em>"+compte+"</em>":"d'identifiant <em>"+$(this).parent().siblings().first().next().text()+"</em>";var categorie=$(this).parent().parent().prevUntil(".categorie").last().prev().text().split(" ")[0];switch(this.className.substring(5)){case"desactive":if(categorie=="Invités")question="Vous allez désactiver le compte invité "+compte+". Cela signifie que le compte ne sera pas supprimé mais sera non utilisable pour une connexion. Les associations éventuelles avec les matières seront conservées. Ce compte sera listé dans la partie inférieure du tableau.";else question="Vous allez désactiver le compte "+compte+". Cela signifie que le compte sera toujours visible pour les professeurs mais que l'utilisateur correspondant ne pourra plus se connecter. <strong>Les notes de colles éventuelles seront conservées. Les données associées au compte seront conservées.</strong><br> Les accès spécifiques éventuels pourront être rétablis en réactivant le compte.<br> Ce compte sera listé dans la partie inférieure du tableau.<br> Cette possibilité est particulièrement utile pour un élève ou un colleur parti en cours d'année et dont il faut conserver les notes de colles.";
-break;case"active":if(categorie=="Invités")question="Vous allez réactiver le compte invité "+compte+". La connexion sera à nouveau possible. Ce compte apparaîtra à nouveau dans la partie principale du tableau.";else question="Vous allez réactiver le compte "+compte+". Cela signifie que l'utilisateur correspondant pourra à nouveau se connecter. Il retrouvera son compte, ses notes de colles éventuelles, ses préférences, ses accès spécifiques éventuels, sans modification. Ce compte apparaîtra à nouveau dans la partie principale du tableau.";break;case"supprutilisateur":if(categorie=="Demandes")question="Vous allez supprimer la demande "+compte+". Cela signifie que cette demande ne conduira pas à une création de compte. Le demandeur ne sera pas prévenu de votre décision.<br> Une fois réalisée, cette opération est définitive, mais rien n'empêche le demandeur d'effectuer une nouvelle demande.<br> <strong>Si vous n'attendez plus de nouvelle demande de création de compte, il est certainement préférable de supprimer cette possibilité à l'aide du réglage accessible en cliquant sur l'icône <span class=\"icon-prefs\"></span> en haut à droite sur cette page</strong>";else if(categorie=="Invitations"){var textecolles=$(this).parent().prev().prev().text()=="Élève"?'<p class="note"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur ce compte seront supprimées. Cette suppression est définitive.</strong></p><p>':"<br>";question="Vous allez supprimer l'invitation "+compte+". Cela signifie que cette invitation ne sera plus valable et que si la personne invitée clique sur le lien reçu par courriel, une erreur apparaîtra devant elle."+textecolles+"<strong>L'invitation envoyée n'a pas de date de péremption&nbsp;: il est n'est pas normal de supprimer l'invitation pour la refaire, à moins de s'être trompé d'adresse électronique. Si la personne invitée vous dit ne pas réussir à s'identifier, proposez-lui de passer par le lien <em>Mot de passe oublié</em>.</strong><br> La personne invitée ne sera pas prévenue de votre décision."}else if(categorie=="Professeurs")question="Vous allez supprimer le compte professeur "+compte+'. <strong>Cela signifie que toutes les préférences de ce compte seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.<br> Les données des matières auxquelles il est associé sont indépendantes&nbsp;: elles ne seront pas supprimées.';else if(categorie=="Administratifs")question="Vous allez supprimer le compte administratif "+compte+". Cela signifie que toutes les préférences de ce compte seront perdues.";else if(categorie=="Colleurs")question="Vous allez supprimer le compte colleur "+compte+'. <strong>Cela signifie que toutes les préférences de ce compte seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Élèves")question="Vous allez supprimer le compte élève "+compte+'. <strong>Cela signifie que toutes les données correspondant à ce compte seront perdues. Les groupes où il apparaît seront modifiés, les notes de colles éventuelles seront supprimées.</strong> <p class="note"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur ce compte seront supprimées. Cette suppression est définitive.<br> Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Invités")question="Vous allez supprimer le compte invité "+compte+". Cela signifie que la connexion par ce compte ne sera plus possible.";else question="Vous allez supprimer le compte "+compte+" déjà désactivé. <strong>Cela signifie que toutes les données correspondant à ce compte seront perdues définitivement. Les groupes où il apparaît seront modifiés, les notes de colles éventuelles seront supprimées.</strong>";if(categorie!="Demandes")question=question+"<br>Une fois réalisée, cette opération est définitive.";break;case"validutilisateur":question="Vous allez valider la demande "+compte+". Son compte sera immédiatement actif et un courriel va immédiatement être envoyé pour le/la prévenir.<br> Il sera automatiquement associé à toutes les matières&nbsp;: <strong>pensez à aller supprimer les matières qui ne le concernent pas sur la page de gestion des associations utilisateurs-matières.</strong>"}confirmation(question,this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateur",modif:el.className.substring(5),id:$(el).parent().parent().data("id")},dataType:"json",el:"",fonction:function(){location.reload(true)}})})}function mail_utilisateurs(){var cases=$(this).parent().parent().nextUntil(".categorie").find(":checked");if(cases.length==0){affiche("<p>Aucune case n'est cochée, aucune action ne peut être réalisée.</p>","nok");return}var ids=cases.map(function(){return $(this).parent().parent().data("id")}).get().join(",");var tds=cases.parent().prev().prev();var val=tds.find(".icon-ok").length>=tds.find(".icon-nok").length?0:1;$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateurs",modif:"mailenvoi",ids:ids,val:val},dataType:"json",el:"",fonction:function(){location.reload(true)}})}function modif_utilisateurs(){var cases=$(this).parent().parent().nextUntil(".categorie").find(":checked");if(cases.length==0){affiche("<p>Aucune case n'est cochée, aucune action ne peut être réalisée.</p>","nok");return}var ids=cases.map(function(){return $(this).parent().parent().data("id")}).get().join(",");var comptes=cases.map(function(){var compte=$(this).parent().siblings().first().text();return compte.length?"<em>"+compte+"</em>":"<em>"+$(this).parent().siblings().first().next().text()+"</em>"}).get().join(", ");var pos=comptes.lastIndexOf(",");if(pos>0)comptes=comptes.substring(0,pos)+" et"+comptes.substring(pos+1);var question="";var categorie=$(this).parent().parent().prev().children().text().split(" ")[0];switch(this.className.substring(5)){case"desactive":if(categorie=="Invités")question="Vous allez désactiver les comptes invités "+comptes+". Cela signifie que ces compte ne seront pas supprimés mais seront non utilisables pour une connexion. Les associations éventuelles avec les matières seront conservées. Ces comptes seront listés dans la partie inférieure du tableau.";else question="Vous allez désactiver le compte "+compte+". Cela signifie que le compte sera toujours visible pour les professeurs mais que l'utilisateur correspondant ne pourra plus se connecter. <strong>Les notes de colles éventuelles seront conservées. Les données associées au compte seront conservées.</strong><br> Les accès spécifiques éventuels pourront être rétablis en réactivant le compte.<br> Ce compte sera listé dans la partie inférieure du tableau.<br> Cette possibilité est particulièrement utile pour un élève ou un colleur parti en cours d'année dont il faut conserver les notes de colles.";question="Vous allez désactiver les comptes de "+comptes+". Cela signifie que ces comptes seront toujours visibles pour les professeurs mais que les utilisateurs correspondant ne pourront plus se connecter. <strong>Les notes de colles éventuelles seront conservées. Les données associées aux comptes seront conservées.</strong><br> Les accès spécifiques éventuels pourront être rétablis en réactivant les comptes.<br> Ces comptes seront listés dans la partie inférieure du tableau.<br> Cette possibilité est particulièrement utile pour des élèves ou des colleurs partis en cours d'année et dont il faut conserver les notes de colles.";break;case"active":if(categorie=="Invités")question="Vous allez réactiver les comptes invité "+comptes+". La connexion sera à nouveau possible. Ces comptes apparaîtront à nouveau dans la partie principale du tableau.";else question="Vous allez réactiver les comptes de "+comptes+". Cela signifie que les utilisateurs correspondant pourront à nouveau se connecter. Ils retrouveront leur compte, leurs notes de colles éventuelles, leurs préférences, leurs accès spécifiques éventuels, sans modification. Ces comptes apparaîtront à nouveau dans la partie principale du tableau.";break;case"supprutilisateur":if(categorie=="Demandes")question="Vous allez supprimer les demandes de "+comptes+". Cela signifie que ces demandes ne conduiront pas à des créations de compte. Les demandeurs ne seront pas prévenus de votre décision.<br> Une fois réalisée, cette opération est définitive, mais rien n'empêche les demandeurs d'effectuer une nouvelle demande.<br> <strong>Si vous n'attendez plus de nouvelle demande de création de compte, il est certainement préférable de supprimer cette possibilité à l'aide du réglage accessible en cliquant sur l'icône <span class=\"icon-prefs\"></span> en haut à droite sur cette page</strong>";else if(categorie=="Invitations"){question="Vous allez supprimer les invitations de "+comptes+". Cela signifie que ces invitations ne seront plus valables et que si les personnes invitées cliquent sur le lien reçu par courriel, une erreur apparaîtra devant elles. <p class=\"note\"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur les comptes de types élèves seront supprimées. Ces suppressions sont définitives.</strong></p> <p><strong>Ces invitations envoyées n'ont pas de date de péremption&nbsp;: il n'est pas normal de supprimer une invitation pour la refaire, à moins de s'être trompé d'adresse électronique. Si une personne invitée vous dit ne pas réussir à s'identifier, proposez-lui de passer par le lien <em>Mot de passe oublié</em>.</strong><br> Les personnes invitées ne seront pas prévenues de votre décision."}else if(categorie=="Professeurs")question="Vous allez supprimer les comptes professeurs de "+comptes+'. <strong>Cela signifie que toutes les préférences de ces comptes seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.<br> Les données des matières auxquelles ces utilisateurs sont associés sont indépendantes&nbsp;: elles ne seront pas supprimées.';else if(categorie=="Administratifs")question="Vous allez supprimer les comptes administratifs de "+comptes+". Cela signifie que toutes les préférences de ces comptes seront perdues.";else if(categorie=="Colleurs")question="Vous allez supprimer les comptes colleurs de "+comptes+'. <strong>Cela signifie que toutes les préférences de ces comptes seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Élèves")question="Vous allez supprimer les comptes élèves de "+comptes+'. <strong>Cela signifie que toutes les données correspondant à ces comptes seront perdues. Les groupes où ils apparaissent seront modifiés, les notes de colles éventuelles seront supprimées.</strong> <p class="note"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur ces compte seront supprimées. Cette suppression est définitive.<br> Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Invités")question="Vous allez supprimer les comptes invités de "+comptes+". Cela signifie que la connexion par ces comptes ne sera plus possible.";else question="Vous allez supprimer les comptes de "+comptes+" déjà désactivés. <strong>Cela signifie que toutes les données correspondant à ces comptes seront perdues définitivement. Les groupes où ils apparaîssent seront modifiés, les notes de colles éventuelles seront supprimées. Dans le cas des comptes professeurs, les données des matières associées ne seront pas supprimées.</strong>";if(categorie!="Demandes")question=question+"<br>Une fois réalisée, cette opération est définitive.";break;case"validutilisateur":question="Vous allez valider les demandes de "+comptes+". Leurs comptes seront immédiatement actifs et un courriel va immédiatement leur être envoyé pour les prévenir.<br> Ils seront automatiquement associés à toutes les matières&nbsp;: <strong>pensez à aller supprimer les matières qui ne les concernent pas sur la page de gestion des associations utilisateurs-matières.</strong>"}confirmation(question,this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateurs",modif:el.className.substring(5),ids:ids},dataType:"json",el:"",fonction:function(){location.reload(true)}})})}}function init_utilisateurs_matieres(){$("tbody tr:not(.categorie) td:not(:first-child,:last-child)").each(function(){var valeurs=this.textContent.split("|");this.innerHTML=valeurs[1]==1?'<a class="icon-ok" data-id="'+valeurs[0]+'" title="Supprimer l\'association à la matière"></a>':'<a class="icon-nok" data-id="'+valeurs[0]+'" title="Établir l\'association à la matière"></a>'});$("tbody tr:not(.categorie) a").on("click",association_um);$(".categorie [data-id]").on("click",association_ums).hide(0);$(".icon-cocher").on("click",cocher_utilisateurs).on("click",majicones);$('input[type="checkbox"]').on("click",majicones).on("change",function(){$(this).parent().parent().removeClass("sel");if(this.checked)$(this).parent().parent().addClass("sel")});$("td:first-child").on("click",function(){$(this).parent().find("input").click()});function majicones(){var tr=$(this).parent().parent();if(!tr.hasClass("categorie"))tr=tr.prevAll(".categorie").first();var cases=tr.nextUntil(".categorie").find(":checked");if(cases.length==0){$("[data-id]",tr).hide(0);return}$("[data-id]",tr).each(function(){var avant=$(this).hasClass("icon-ok");var apres=cases.parent().prevAll().find('.icon-ok[data-id="'+this.getAttribute("data-id")+'"]').length<cases.length/2;if(avant!=apres)$(this).toggleClass("icon-ok icon-nok").attr("title",(apres?"Établir":"Supprimer")+" l'association à la matière de tous les cochés")}).show(0)}function association_um(){var val=$(this).hasClass("icon-ok");$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateur-matiere",id:$(this).parent().parent().data("id"),matiere:$(this).data("id"),val:1-val},dataType:"json",el:$(this),fonction:function(el){el.toggleClass("icon-ok icon-nok").attr("title",(val?"Établir":"Supprimer")+" l'association à la matière")}})}function association_ums(){var cases=$(this).parent().parent().nextUntil(".categorie").find(":checked");if(cases.length==0){affiche("<p>Aucune case n'est cochée, aucune action ne peut être réalisée.</p>","nok");return}var ids=cases.map(function(){return $(this).parent().parent().data("id")}).get().join(",");var comptes=cases.map(function(){return $(this).parent().siblings().first().text().split("(")[0].trim()}).get().join(", ");var pos=comptes.lastIndexOf(",");if(pos>0)comptes=comptes.substring(0,pos)+" et"+comptes.substring(pos+1);var val=$(this).hasClass("icon-ok");var mid=this.getAttribute("data-id");var question=val?"Vous allez établir l'association à la matière "+$("#m"+mid).text()+" pour les comptes de "+comptes+". Cela signifie que ces utilisateurs auront accès aux ressources liées à cette matière, en fonction de l'autorisation que vous avez fixée pour ces ressources.":"Vous allez supprimer l'association à la matière "+$("#m"+mid).text()+" pour les comptes de "+comptes+". Cela signifie que ces utilisateurs n'auront plus accès aux ressources liées à cette matière. Si des notes de colles ont été saisies, elles seront automatiquement et définitivement supprimées de la base.";confirmation(question,this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateurs-matieres",ids:ids,matiere:mid,val:val|0},dataType:"json",el:"",fonction:function(el){location.reload(true)}})})}}function init_utilisateurs_groupes(){$('article input[type="checkbox"]').on("change",function(){$.ajax({url:"ajax.php",method:"post",data:{action:"groupes",champ:this.id.substr(0,5),id:this.id.substr(5),val:this.checked|0},dataType:"json",el:"",fonction:function(el){return true}})});$(".usergrp span").append('&nbsp;<a class="icon-edite" title="Éditer les utilisateurs de ce groupe"></a>').on("click",utilisateursgroupe)}function utilisateursgroupe(){popup($("#form-utilisateurs").html(),true);var f=$("#fenetre");var span=$(this);article=span.parent().parent();$("table",f).attr("id","utilisateurs");$("h3",f).append($(".editable",article).text()||$("input:first",article).val());$(".icon-deplie",f).on("click",plie);$(".icon-cocher",f).on("click",cocher_utilisateurs);$("tr:not(.categorie)",f).on("click",function(e){if(!$(e.target).is("input"))$(this).find("input").click()});$("input",f).on("change",function(){$(this).parent().parent().removeClass("sel");if(this.checked)$(this).parent().parent().addClass("sel")});var ids=span.data("uids");$("#u"+ids.replace(/,/g,",#u"),f).prop("checked",true).change();$(".icon-ok",f).on("click",function(){var ids=$("input:checked",f).map(function(){return this.id.replace("u","")}).get().join(",");var noms=$("input:checked",f).parent().prev().map(function(){return this.textContent.split("(")[0].trim()}).get().join(", ")||"[Personne]";if(article.is("div")){$("#uids",article).val(ids);span.data("uids",ids);span.html(noms+'&nbsp;<a class="icon-edite" title="Éditer les utilisateurs de ce groupe"></a>');$("#fenetre, #fenetre_fond").remove()}else $.ajax({url:"ajax.php",method:"post",data:{action:"groupes",champ:"utilisateurs",id:article.data("id").split("|")[1],uids:ids},dataType:"json",el:span,fonction:function(el){el.data("uids",ids);el.html(noms+'&nbsp;<a class="icon-edite" title="Éditer les utilisateurs de ce groupe"></a>');$("#fenetre, #fenetre_fond").remove()}})})}function suppressionmultiple(){var prop=$(this).data("id").split("|");var contexte=$(this).parent().find("h3").text();var item="";switch(prop[2]){case"infos":item="toutes les informations de la page <em>"+contexte+"</em>";break;case"colles":item="tous les programmes de colles de la matière <em>"+contexte+"</em>";break;case"cdt":item="tout le contenu du cahier de texte de la matière <em>"+contexte+"</em>";break;case"docs":item="tous les répertoires et documents de la matière <em>"+contexte+"</em>";break;case"notes":item="toutes les notes de la matière <em>"+contexte+"</em>";break}confirmation("Vous allez supprimer XXX.<br>Cette opération n'est pas annulable.".replace("XXX",item),this,function(el){$.ajax({url:"ajax.php",method:"post",data:"action="+prop[0]+"&id="+prop[1]+"&supprime_"+prop[2]+"=1",dataType:"json",el:$(el),fonction:function(el){el.remove()}})})}function destinatairesmail(){popup($("#form-destinataires").html(),true);var f=$("#fenetre");$("table",f).attr("id","utilisateurs");$(".icon-deplie",f).on("click",plie);$("tr:not(.gr) input.dest",f).attr("id",function(){return"u"+this.value});$("tr:not(.categorie) td:nth-child(-n+2)",f).on("click",function(e){if(!$(e.target).is("input"))$(this).parent().find("input:first").click()});$("input",f).on("change",function(){var tr=$(this).parent().parent().removeClass("sel");if(this.checked)tr.find("input:not(."+this.className+")").prop("checked",false);if(tr.find("input:checked").length)tr.addClass("sel")});var ids=$('[name="id-copie"]').val();$("#u"+ids.replace(/,/g,",#u")).prop("checked",true).change();ids=$('[name="id-bcc"]').val();$("#u"+ids.replace(/,/g,",#u")).parent().next().children().prop("checked",true).change();$(".categorie a",f).on("click keyup",function(){var classe=this.className.split(" ")[1];var etat=this.className.split(" ")[0]=="icon-cocher";var titre=this.title;$(this).parent().parent().nextUntil(".categorie").find("."+classe+":not(:disabled)").prop("checked",etat).change();this.className=(etat?"icon-decocher ":"icon-cocher ")+classe;this.title=this.title.replace(etat?"Cocher":"Décocher",etat?"Décocher":"Cocher");var classe2=classe=="dest"?"bcc":"dest";$(this).parent().parent().find(".icon-decocher."+classe2).each(function(){this.className="icon-cocher "+classe2;this.title="C"+this.title.substr(3)})});$(".gr input",f).on("click",function(){var ids=this.value;if(this.className=="dest")$("#u"+ids.replace(/,/g,",#u")).prop("checked",this.checked).change();else $("#u"+ids.replace(/,/g,",#u")).parent().next().children().prop("checked",this.checked).change()});$(".icon-ok",f).on("click",function(){$('[name="id-copie"]').val($("tr:not(.gr) .dest:checked",f).map(function(){return this.value}).get().join(","));$('[name="id-bcc"]').val($("tr:not(.gr) .bcc:checked",f).map(function(){return this.value}).get().join(","));$("#maildest").text($("tr:not(.gr) .dest:checked",f).parent().prev().map(function(){return this.textContent}).get().concat($("tr:not(.gr) .bcc:checked",f).parent().prev().prev().map(function(){return this.textContent+" (CC)"}).get()).join(", ")||"[Personne]");$("#fenetre, #fenetre_fond").remove()})}function envoimail(){if($(".maildest").children("span").text()=="[Personne]")affiche("Il faut au moins un destinataire pour envoyer le courriel.","nok");else if(!$('[name="sujet"]').val().length)affiche("Il faut un sujet non vide pour envoyer le courriel.","nok");else $.ajax({url:"ajax.php",method:"post",data:$("#mail").serialize(),dataType:"json",el:"",fonction:function(el){location.reload(true)}})}function relevenotes(){confirmation("<p>Vous allez réaliser une relève des notes de colles. Cela consiste à marquer comme relevées toutes les heures déclarées jusqu'à maintenant et non encore relevées. Vous pourrez alors télécharger le nouveau relevé au sein du tableau en bas de page.</p><p>Cette opération n'est pas annulable.</p><p>Une fois que vous aurez réalisé ce relevé, les professeurs et colleurs ne pourront pas modifier le nombre d'élèves et la durée correspondant aux colles relevées.</p>",this,function(el){$.ajax({url:"ajax.php",method:"post",data:"action=releve-notes",dataType:"json",el:"",fonction:function(el){location.reload(true)}})})}$(document).ajaxSend(function(ev,xhr,settings){$("#load").show(200);if(settings.data.append)settings.data.append("csrf-token",$("body").attr("data-csrf-token"));else settings.data="csrf-token="+$("body").attr("data-csrf-token")+"&"+settings.data}).ajaxStop(function(){$("#load").hide(200)}).ajaxSuccess(function(ev,xhr,settings){var data=xhr.responseJSON;switch(data["etat"]){case"ok":affiche(data["message"],"ok");settings.fonction(settings.el);break;case"nok":affiche(data["message"],"nok");break;case"login":case"mdp":reconnect(settings,data["etat"]=="mdp");break;case"recupok":settings.afficheform(data)}});$(function(){$("a.formulaire, .modifevnmt").on("click",formulaire);$("a.icon-aide").on("click",function(){popup($("#aide-"+($(this).parent().data("id")||"page").split("|")[0]).html(),false)});$("a.icon-ok").on("click",valide);$("a.icon-cache,a.icon-montre,a.icon-monte,a.icon-descend,a.icon-supprime,a.icon-lock,a.icon-ajoutecolle").on("click",function(){window[this.className.substring(5)]($(this))});$("#log").hide().on("click",function(){$(this).hide(300)});$(".editable").editinplace();$("a.icon-deconnexion").on("click",function(e){$.ajax({url:"ajax.php",method:"post",data:{action:"deconnexion"},dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$(".titrecdt").editinplacecdt();$(".cdt-raccourcis").init_cdt_raccourcis();$(".icon-mailenvoi").on("click",envoimail);$("#maildest, #maildest + .icon-edite").on("click",destinatairesmail);$(".categorie th:first-child").prepend($('<span class="icon-deplie" title="Déplier/Replier cette catégorie"></span>').on("click",plie));$("article select[multiple]").each(selmult);$(".supprmultiple").on("click",suppressionmultiple);$("#utilisateurs").each(init_utilisateurs);$("#utilisateurs-matieres").each(init_utilisateurs_matieres);$(".usergrp").first().each(init_utilisateurs_groupes);$("#planning select").change(function(){$(this).parent().prev().children("input").prop("checked",this.value==0)});$("#planning input").change(function(){$(this).parent().next().children("select").val(0)});$("#relevenotes").on("click",relevenotes);$(".icon-menu").on("click",function(){$("#colonne,nav").toggleClass("visible")})});
\ No newline at end of file
+function affiche(message,etat){$("#log").removeClass().addClass(etat).html(message).append('<span class="icon-ferme"></span>').fadeIn().off("click").on("click",function(){window.clearTimeout(extinction);$(this).fadeOut(800)});extinction=window.setTimeout(function(){$("#log").fadeOut(800)},6e3)}function reconnect(settings,light){$("#fenetre,#fenetre_fond").remove();if(settings.url=="recup.php")var action=settings.data.indexOf("prefs")?"récupérer les préférences de cet utilisateur":"récupérer la liste des répertoires et documents disponibles";else{var action="valider cette action";settings.afficheform=Function.prototype}if(light)popup('<a class="icon-ok" title="Valider"></a><h3>Connexion nécessaire</h3>           <p>Votre connexion est active, mais vous devez saisir de nouveau votre mot de passe pour '+action+'.</p>           <form>           <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepasse"></p>           </form>',true);else popup('<a class="icon-ok" title="Valider"></a><h3>Connexion nécessaire</h3>           <p>Votre connexion a été automatiquement désactivée. Vous devez vous connecter à nouveau pour '+action+'.</p>           <form>           <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" name="login" id="login"></p>           <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepasse"></p>           </form>',true);$("#fenetre input:first").focus();$("#fenetre a.icon-ok").on("click",function(){$.ajax({url:settings.url,method:"post",data:$("#fenetre form").serialize()+"&"+settings.data,dataType:"json",el:settings.el,afficheform:settings.afficheform,fonction:settings.fonction}).done(function(data){if(data["etat"]!="mdpnok")$("#fenetre,#fenetre_fond").remove()})});$("#fenetre a.icon-ferme").on("click",function(){affiche("Modification non effectuée, connexion nécessaire","nok")});$("#fenetre input").on("keypress",function(e){if(e.which==13){$("#fenetre a.icon-ok").click();return false}})}function popup(contenu,modal){$("#fenetre,#fenetre_fond").remove();var el=$('<article id="fenetre"></article>').appendTo("body").html(contenu).focus();if(modal)$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});else $('<a class="icon-epingle" title="Épingler à la page"></a>').prependTo(el).on("click",function(){$("#fenetre_fond").remove();$(this).remove();el.removeAttr("id").insertBefore($("article,#calendrier,#parentsdoc+*").first())});$('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function(){el.remove();$("#fenetre_fond").remove()})}function confirmation(question,element,action){popup("<h3>Demande de confirmation</h3><p>"+question+'</p><p class="confirmation"><button class="icon-ok"></button>&nbsp;&nbsp;&nbsp;<button class="icon-annule"></button></p>',true);$("#fenetre .icon-ok").on("click",function(){action(element);$("#fenetre,#fenetre_fond").remove()});$("#fenetre .icon-annule").on("click",function(){$("#fenetre,#fenetre_fond").remove()})}function plie(){var lignes=$(this).parent().parent().nextUntil(".categorie");if($(this).hasClass("icon-deplie")){lignes.children().wrapInner("<div></div>").addClass("cache");lignes.find("div").slideUp(1e3);window.setTimeout(function(){lignes.hide().children().html(function(){return $(this).children().html()})},1e3)}else{lignes.show();lignes.children().wrapInner('<div style="display:none;"></div>');lignes.find("div").slideDown(1e3);window.setTimeout(function(){lignes.children().html(function(){return $(this).children().html()}).removeClass("cache")},1e3)}$(this).toggleClass("icon-plie icon-deplie")}$.fn.textareahtml=function(){this.each(function(){var ta=$(this);var placeholder=this.getAttribute("placeholder");this.setAttribute("placeholder",placeholder+". Formattage en HTML, balises visibles.");var ce=$('<div contenteditable="true" placeholder="'+placeholder+'"></div>').insertAfter(ta.before(boutons)).hide();var boutonretour=ta.prev().children(".icon-retour");if(ta.hasClass("ligne")){ce.addClass("ligne");ta.prev().addClass("ligne")}ta.on("keypress",function(e){if(e.which==13)this.value=nettoie(this.value)}).on("paste cut",function(){var el=this;setTimeout(function(){el.value=nettoie(el.value)},100)});ce.on("keypress",function(e){if(e.which==13)boutonretour.click()}).on("paste cut",function(){var el=this;setTimeout(function(){el.innerHTML=nettoie(el.innerHTML)+"<br>"},100)});ta.prev().children(".icon-nosource").on("click",function(e){e.preventDefault();ta.hide();ce.show().css("min-height",ta.outerHeight());$(this).hide().prev().show();ce.focus().html(nettoie(ta.val())).change();if(window.getSelection){var r=document.createRange();r.selectNodeContents(ce[0]);r.collapse(false);var s=window.getSelection();s.removeAllRanges();s.addRange(r)}else{var r=document.body.createTextRange();r.moveToElementText(ce[0]);r.collapse(false);r.select()}});ta.prev().children(".icon-source").on("click",function(e){e.preventDefault();ce.hide(0);ta.show(0).css("height",ce.height());$(this).hide().next().show();ta.focus().val(nettoie(ce.html()))}).hide();ta.prev().children(".icon-aide").on("click",function(e){e.preventDefault();aidetexte()});ta.prev().children().not(".icon-nosource,.icon-source,.icon-aide").on("click",function(e){e.preventDefault();window["insertion_"+this.className.substring(5)]($(this))})})};$.fn.editinplace=function(){this.each(function(){var el=$(this);el.data("original",el.is("h3")?el.text():el.html());$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transforme)})};function transforme(){var el=$(this).parent().addClass("avecform");if(el.is("div")){if(el.hasClass("majpubli"))el.html('<form><textarea name="val" rows="'+(el.data("original").split(/\r\n|\r|\n/).length+3)+'"></textarea><p class="ligne"><label for="publi">Publier en tant que mise à jour&nbsp;: </label><input type="checkbox" id="publi" name="publi" value="1" checked></p></form>');else el.html('<form><textarea name="val" rows="'+(el.data("original").split(/\r\n|\r|\n/).length+3)+'"></textarea></form>');$("textarea:visible").on("change",function(e){$("body").data("nepassortir",true);$(this).off(e)})}else el.html('<form class="edition" onsubmit="$(this).children(\'a.icon-ok\').click(); return false;"><input type="text" name="val" value=""></form>');var input=el.find('[name="val"]').val(el.data("original")).attr("placeholder",el.attr("placeholder"));if(el.hasClass("edithtml"))input.textareahtml();$('<a class="icon-ok" title="Valider"></a>').appendTo(el.children()).on("click",function(){var id=el.data("id").split("|");if(el.hasClass("edithtml"))input.val(nettoie(input.is(":visible")?input.val():input.next().html()));$.ajax({url:"ajax.php",method:"post",data:{action:id[0],champ:id[1],id:id[2],val:input.val(),publi:el.find(":checkbox").is(":checked")||undefined},dataType:"json",el:el,fonction:function(el){var val=el.find('[name="val"]').val();el.removeClass("avecform").html(val).data("original",val);$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transforme)}})});$('<a class="icon-annule" title="Annuler"></a>').appendTo(el.children()).on("click",function(){el.removeClass("avecform").html(el.data("original"));$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transforme)});input.focus().val(el.hasClass("edithtml")?nettoie(input.val()):input.val())}$.fn.editinplacecdt=function(){this.each(function(){$(this).wrapInner("<span></span>").data("original",$(this).text());$('<a class="icon-edite" title="Modifier"></a>').appendTo($(this)).on("click",transformecdt)})};function transformecdt(){var el=$(this).parent();$(".icon-edite",el).remove();var form=$('<form class="titrecdt"></form>').insertBefore(el.parent().children("div")).html($("#form-cdt").html());$("input, select",form).attr("id",function(){return this.getAttribute("name")});var valeurs=el.data("donnees");for(var cle in valeurs)$("#"+cle).val(valeurs[cle]);form.init_cdt_boutons();$("textarea",form).on("change",function(e){$("body").data("nepassortir",true);$(this).off(e)});$("input,#demigroupe",form).on("change keyup",function(){var t=new Date($("#jour").val().replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));var dg=$("#demigroupe").val()==1?" (en demi-groupe)":"";switch(parseInt(seances[$("#tid").val()])){case 0:var titre=jours[t.getDay()]+" "+$("#jour").val()+" à "+$("#h_debut").val()+" : "+$("#tid option:selected").text()+dg;break;case 1:var titre=jours[t.getDay()]+" "+$("#jour").val()+" de "+$("#h_debut").val()+" à "+$("#h_fin").val()+" : "+$("#tid option:selected").text()+dg;break;case 2:var titre=jours[t.getDay()]+" "+$("#jour").val()+" : "+$("#tid option:selected").text()+" pour le "+$("#pour").val()+dg;break;case 3:var titre=jours[t.getDay()]+" "+$("#jour").val()+" : "+$("#tid option:selected").text()+dg;break;case 4:var titre=jours[t.getDay()]+" "+$("#jour").val();break;case 5:var titre="[Entrée hebdomadaire]"}$("span",el).text(titre)});$('<a class="icon-ok" title="Valider"></a>').appendTo(el).on("click",function(){var id=el.parent().data("id").split("|");$.ajax({url:"ajax.php",method:"post",data:"action=cdt-elems&id="+id[1]+"&"+form.serialize(),dataType:"json",el:el,fonction:function(el){var form=el.siblings("form");el.data("original",$("span",el).text()).data("donnees",{tid:$("#tid").val(),jour:$("#jour").val(),h_debut:$("#h_debut").val(),h_fin:$("#h_fin").val(),pour:$("#pour").val(),demigroupe:$("#demigroupe").val()});form.remove();$("a",el).remove();$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transformecdt)}}).done(function(data){if(data["etat"]=="ok"&&data["reload"]=="oui")location.reload(true)})});$('<a class="icon-annule" title="Annuler"></a>').appendTo(el).on("click",function(){form.remove();$("span",el).html(el.data("original"));$("a",el).remove();$('<a class="icon-edite" title="Modifier"></a>').appendTo(el).on("click",transformecdt)})}function nettoie(html){if(html.indexOf("cdptmp")>0){var tmp=$("<div>"+html+"</div>");tmp.find(".cdptmp").contents().unwrap();html=tmp.html();if(html.indexOf("cdptmp")>0)html=html.replace(/<span class="cdptmp"><\/span>/g,"")}return html.replace(/(<\/?[A-Z]+)([^>]*>)/g,function(tout,x,y){return x.toLowerCase()+y}).replace(/[\r\n ]+/g," ").replace(/(<br>)+[ ]?<\/(p|div|li|h)/g,function(tout,x,y){return"</"+y}).replace(/<br>/g,"<br>\n").replace(/<(p|div|li|h)/g,function(x){return"\n"+x}).replace(/<\/(p|div|li|h.)>/g,function(x){return x+"\n"}).replace(/<\/?(ul|ol)[^>]*>/g,function(x){return"\n"+x+"\n"}).replace(/^(?!(<p|<div|<ul|<ol|<li|<h))(.+)<br>$/gm,function(tout,x,y){return"<p>"+y+"</p>"}).replace(/^(?!(<(p|div|ul|ol|li)))[ ]?(.+)[ ]?$/gm,function(t,x,y,z){return z.match(/.*(p|div|ul|ol|li|h.)>$/)?z:"<p>"+z+"</p>"}).replace(/^[ ]?(<\/?(br|p|div|h.)>){0,2}[ ]?(<\/(p|div|h.)>)?[ ]?$/gm,"").replace(/^\n/gm,"").replace(/<li/g,"  <li")}function insert(el,debut,fin,milieu){var contenant=el.parent().siblings("textarea,[contenteditable]").filter(":visible")[0];if(!contenant.hasAttribute("data-selection"))marqueselection(el);var texte=milieu===undefined?debut+"Í"+contenant.getAttribute("data-selection")+"Ì"+fin:debut+"Í"+milieu+"Ì"+fin;var contenu=nettoie(contenant.getAttribute("data-contenu").replace(/Í.*Ì/,texte));if(contenant.tagName=="TEXTAREA")contenant.value=contenu.replace(/[ÍÌ]/g,"");else contenant.innerHTML=contenu.replace(/[ÍÌ]/g,"");marqueselection(el,true);if(contenant.tagName=="TEXTAREA"&&contenant.selectionStart!==undefined){contenant.selectionStart=contenu.indexOf("Í");contenant.selectionEnd=contenu.indexOf("Ì")-1;contenant.focus()}else if(document.selection){if(contenant.tagName!="TEXTAREA")contenu=contenu.replace(/(<([^>]+)>)[\n]*/g,"");range=document.body.createTextRange();range.moveToElementText(contenant);range.collapse(true);range.moveEnd("character",contenu.indexOf("Ì")-1);range.moveStart("character",contenu.indexOf("Í"));range.select()}else if(window.getSelection){contenant.innerHTML=contenu.replace("Í",'<span class="cdptmp">').replace("Ì","</span>")+"<br>";selection=window.getSelection();range=document.createRange();range.selectNodeContents($(contenant).find(".cdptmp")[0]);selection.removeAllRanges();selection.addRange(range);contenant.focus()}}function marqueselection(el,efface){var contenant=el.parent().siblings("textarea,[contenteditable]").filter(":visible")[0];if(efface){contenant.removeAttribute("data-selection");contenant.removeAttribute("data-contenu");return true}var original=contenant.tagName=="TEXTAREA"?contenant.value:contenant.innerHTML;var sel="";if(contenant.tagName=="TEXTAREA"&&contenant.selectionStart!==undefined){contenant.focus();sel=contenant.value.substring(contenant.selectionStart,contenant.selectionEnd);contenant.value=contenant.value.substr(0,contenant.selectionStart)+"Í"+sel+"Ì"+contenant.value.substring(contenant.selectionEnd)}else if(window.getSelection){var range=window.getSelection().getRangeAt(0);if(contenant==range.commonAncestorContainer||$.contains(contenant,range.commonAncestorContainer)){var sel=window.getSelection().toString();range.deleteContents();range.insertNode(document.createTextNode("Í"+sel+"Ì"))}}else{var range=document.selection.createRange();if(contenant==range.parentElement()||$.contains(contenant,range.parentElement())){var sel=document.selection.createRange().text;document.selection.createRange().text="Í"+sel+"Ì"}}if(contenant.tagName=="TEXTAREA"){var contenu=contenant.value;contenant.value=original}else{var contenu=contenant.innerHTML;$(contenant).html(original)}if(contenu.indexOf("Ì")<0)contenu=contenu+"ÍÌ";contenant.setAttribute("data-selection",sel);contenant.setAttribute("data-contenu",contenu);return sel}var boutons='<p class="boutons">  <button class="icon-titres" title="Niveaux de titres"></button>  <button class="icon-par1" title="Paragraphe"></button>  <button class="icon-par2" title="Paragraphe important"></button>  <button class="icon-par3" title="Paragraphe très important"></button>  <button class="icon-retour" title="Retour à la ligne"></button>  <button class="icon-gras" title="Gras"></button>  <button class="icon-italique" title="Italique"></button>  <button class="icon-souligne" title="Souligné"></button>  <button class="icon-omega" title="Insérer une lettre grecque"></button>  <button class="icon-sigma" title="Insérer un signe mathématique"></button>  <button class="icon-exp" title="Exposant"></button>  <button class="icon-ind" title="Indice"></button>  <button class="icon-ol" title="Liste énumérée"></button>  <button class="icon-ul" title="Liste à puces"></button>  <button class="icon-lien1" title="Lien vers un document du site"></button>  <button class="icon-lien2" title="Lien internet"></button>  <button class="icon-tex" title="LATEX!"></button>  <button class="icon-source" title="Voir et éditer le code html"></button>  <button class="icon-nosource" title="Voir et éditer le texte formaté"></button>  <button class="icon-aide" title="Aide pour cet éditeur de texte"></button></p>';function insertion_titres(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'un titre</h3>  <p>Choisissez le type du titre ci-dessous. Vous pouvez éventuellement modifier le texte (ou pourrez le faire ultérieurement). Il est conseillé d\'utiliser des titres de niveau 2 pour les titres dans les programmes de colle.</p>  <input type="radio" name="titre" id="t3" value="3" checked><h3><label for="t3">Titre de niveau 1 (pour les I,II...)</label></h3><br>  <input type="radio" name="titre" id="t4" value="4"><h4><label for="t4">Titre de niveau 2 (pour les 1,2...)</label></h4><br>  <input type="radio" name="titre" id="t5" value="5"><h5><label for="t5">Titre de niveau 3 (pour les a,b...)</label></h5><br>  <input type="radio" name="titre" id="t6" value="6"><h6><label for="t6">Titre de niveau 4</label></h6><br>  <p class="ligne"><label for="texte">Texte&nbsp;: </label><input type="text" id="texte" value="'+marqueselection(el)+'" size="80"></p>  <hr><h3>Aperçu</h3><div id="apercu"></div>',true);$("#fenetre input").on("click keyup",function(){var balise="h"+$("[name='titre']:checked").val();$("#apercu").html("<"+balise+">"+($("#texte").val().length?$("#texte").val():"Texte du titre")+"</"+balise+">")}).first().keyup();$("#texte").on("keypress",function(e){if(e.which==13)$("#fenetre a.icon-ok").click()}).focus();$("#fenetre a.icon-ok").on("click",function(){var balise="h"+$("[name='titre']:checked").val();insert(el,"<"+balise+">","</"+balise+">",$("#texte").val());$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_omega(el){popup("<h3>Insertion d'une lettre grecque</h3>  <p>Cliquez sur la lettre à insérer&nbsp;:</p>  <button>&alpha;</button> <button>&beta;</button> <button>&gamma;</button> <button>&Delta;</button> <button>&delta;</button> <button>&epsilon;</button> <button>&eta;</button> <button>&Theta;</button> <button>&theta;</button> <button>&Lambda;</button> <button>&lambda;</button> <button>&mu;</button> <button>&nu;</button> <button>&xi;</button> <button>&Pi;</button> <button>&pi;</button> <button>&rho;</button> <button>&Sigma;</button> <button>&sigma;</button> <button>&tau;</button> <button>&upsilon;</button> <button>&Phi;</button> <button>&phi;</button> <button>&Psi;</button> <button>&psi;</button> <button>&Omega;</button> <button>&omega;</button>",true);$("#fenetre button").on("click",function(){insert(el,"","",$(this).text());$("#fenetre,#fenetre_fond").remove()})}function insertion_sigma(el){popup("<h3>Insertion d'un symbole mathématique</h3>  <p>Cliquez sur le symbole à insérer&nbsp;:</p>  <button>&forall;</button> <button>&exist;</button> <button>&part;</button> <button>&nabla;</button> <button>&prod;</button> <button>&sum;</button> <button>&plusmn;</button> <button>&radic;</button> <button>&infin;</button> <button>&int;</button> <button>&prop;</button> <button>&sim;</button> <button>&cong;</button> <button>&asymp;</button> <button>&ne;</button> <button>&equiv;</button> <button>&le;</button> <button>&ge;</button> <button>&sub;</button> <button>&sup;</button> <button>&nsub;</button> <button>&sube;</button> <button>&supe;</button> <button>&isin;</button> <button>&notin;</button> <button>&ni;</button> <button>&oplus;</button> <button>&otimes;</button> <button>&sdot;</button> <button>&and;</button> <button>&or;</button> <button>&cap;</button> <button>&cup;</button> <button>&real;</button> <button>&image;</button> <button>&empty;</button> <button>&deg;</button> <button>&prime;</button> <button>&micro;</button> <button>&larr;</button> <button>&uarr;</button> <button>&rarr;</button> <button>&darr;</button> <button>&harr;</button> <button>&lArr;</button> <button>&uArr;</button> <button>&rArr;</button> <button>&dArr;</button> <button>&hArr;</button>",true);$("#fenetre button").on("click",function(){insert(el,"","",$(this).text());$("#fenetre,#fenetre_fond").remove()})}function insertion_ol(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'une liste numérotée</h3>  <p>Choisissez le type de numérotation et la valeur de départ de la liste ci-dessous. Vous pouvez éventuellement modifier les différents éléments en les écrivant ligne par ligne. Vous pourrez ajouter un élément ultérieurement en l\'encadrant par les balises &lt;li&gt; et &lt;/li&gt;.</p>  <p class="ligne"><label for="t1">Numérotation numérique (1, 2, 3...)</label><input type="radio" name="type" id="t1" value="1" checked></p>  <p class="ligne"><label for="t2">Numérotation alphabétique majuscule (A, B, C...)</label><input type="radio" name="type" id="t2" value="A"></p>  <p class="ligne"><label for="t3">Numérotation alphabétique minuscule (a, b, c...)</label><input type="radio" name="type" id="t3" value="a"></p>  <p class="ligne"><label for="t4">Numérotation romaine majuscule (I, II, III...)</label><input type="radio" name="type" id="t4" value="I"></p>  <p class="ligne"><label for="t5">Numérotation romaine minuscule (i, ii, iii...)</label><input type="radio" name="type" id="t5" value="i"></p>  <p class="ligne"><label for="debut">Valeur de début (numérique)</label><input type="text" id="debut" value="1"></p>  <p class="ligne"><label for="lignes">Textes (chaque ligne correspond à un élément de la liste)&nbsp;: </label></p>  <textarea id="lignes" rows="5">'+marqueselection(el)+'</textarea>  <hr><h3>Aperçu</h3><div id="apercu"></div>',true);$("#fenetre :input").on("click keyup",function(){var debut=$("#debut").val();debut=debut.length&&debut>1?' start="'+debut+'"':"";$("#apercu").html('<ol type="'+$("[name='type']:checked").val()+'"'+debut+"><li>"+($("#lignes").val().length?$("#lignes").val().trim("\n").replace(/\n/g,"</li><li>"):"Première ligne</li><li>Deuxième ligne</li><li>...")+"</li></ol>")}).first().keyup();$("#lignes").focus();$("#fenetre a.icon-ok").on("click",function(){var debut=$("#debut").val();debut=debut.length&&debut>1?' start="'+debut+'"':"";var elements=$("#lignes").val().trim("\n");var index=elements.lastIndexOf("\n");if(index>0){var dernier=elements.substring(index+1);elements=elements.substring(0,index)}else var dernier="";insert(el,'<ol type="'+$("[name='type']:checked").val()+'"'+debut+"><li>"+elements.replace(/\n/g,"</li><li>")+"</li><li>","</li></ol>",dernier);$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_ul(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'une liste à puces</h3>  <p>Vous pouvez éventuellement modifier les différents éléments en les écrivant ligne par ligne (chaque ligne correspond à un élément de la la liste). Vous pourrez ajouter un élément ultérieurement en l\'encadrant par les balises &lt;li&gt; et &lt;/li&gt;.</p>  <textarea id="lignes" rows="5">'+marqueselection(el)+'</textarea>  <hr><h3>Aperçu</h3><div id="apercu"></div>',true);$("#lignes").on("click keyup",function(){$("#apercu").html("<ul><li>"+($("#lignes").val().length?$("#lignes").val().trim("\n").replace(/\n/g,"</li><li>"):"Première ligne</li><li>Deuxième ligne</li><li>...")+"</li></ul>")}).keyup().focus();$("#fenetre a.icon-ok").on("click",function(){var elements=$("#lignes").val().trim("\n");var index=elements.lastIndexOf("\n");if(index>0){var dernier=elements.substring(index+1);elements=elements.substring(0,index)}else var dernier="";insert(el,"<ul><li>"+elements.replace(/\n/g,"</li><li>")+"</li><li>","</li></ul>",dernier);$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_lien1(el){var sel=marqueselection(el);popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'un lien vers un document de Cahier de Prépa</h3>  <div><p style="text-align:center; margin: 2em 0;">[Récupération des listes de documents]</p></div>  <div style="display:none;"><hr><h3>Aperçu</h3><div id="apercu" style="text-align:center;">[Veuillez choisir un document]</div></div>',true);$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)});$.ajax({url:"recup.php",method:"post",data:{action:"docs"},dataType:"json"}).done(function(data){var majapercu=function(){var apercu=$("#apercu");var id=$("#doc").val();var texte=$("#doc option:selected").text();if(id==0)apercu.html(texte);else if($("#vue").is(":checked")){var l=$("#largeur").val();if(texte.slice(-4,-1)=="pdf"){if(apercu.children(".pdf").length==0)apercu.html('<div><object data="download?id='+id+'" type="application/pdf" height="100%" width="100%"> <a href="download?id='+id+'">'+texte+"</a> </object></div>");else if(apercu.find("object").attr("data").substr(12)!=id)apercu.find("object").attr("data","download?id="+id).html('<a href="download?id='+id+'">'+texte+"</a>");apercu.children().attr("class","pdf "+$("#format").val());if(l){if(l==100)apercu.children().removeAttr("style").children().attr("width","100%").removeAttr("style");else{apercu.children().css("padding-bottom",$('<div class="'+$("#format").val()+'"></div>').css("padding-bottom").slice(0,-1)*l/100+"%");apercu.find("object").attr("width",l+"%").css("left",(100-l)/2+"%")}}}else if("jpgpegpng".indexOf(texte.slice(-4,-1))>-1){if(apercu.children("img").length==0)apercu.css("text-align","").html('<img src="download?id='+id+'">');else if(apercu.children().attr("src").substr(12)!=id)apercu.children().attr("src","download?id="+id);if(l){if(l==100)apercu.children().removeAttr("style");else apercu.children().css("width",l+"%").css("margin-left",(100-l)/2+"%")}}}else $("#apercu").css("text-align","center").html('<a onclick="return false;" href="download?id='+this.value+'">'+$("#texte").val()+"</a>")};var affichedocs=function(data){$("#fenetre > div:first").html('  <p>Choisissez ci-dessous le répertoire puis le document à insérer. Vous pouvez aussi modifier le texte visible. Cela reste modifiable ultérieurement&nbsp;: le texte est situé entre les deux balises &lt;a...&gt; et &lt;/a&gt;.</p>  <p class="ligne"><label for="mat">Matière&nbsp;:</label><select id="mat">'+data.mats+'</select></p>  <p class="ligne"><label for="rep">Répertoire&nbsp;:</label><select id="rep"></select></p>  <p class="ligne"><label for="doc">Document&nbsp;:</label><select id="doc"></select></p>  <p class="ligne"><label for="texte">Texte visible&nbsp;:</label><input type="text" id="texte" value="'+sel+'" size="80" data-auto="1"></p>  <p class="ligne"><label for="vue">Afficher dans la page (PDF et image uniquement)</label><input type="checkbox" id="vue">  <p class="ligne"><label for="largeur">Largeur en %&nbsp;:</label><input type="text" id="largeur" value="100" size="3"></p>  <p class="ligne"><label for="format">Format (PDF uniquement)</label><select id="format">    <option value="portrait">A4 vertical</option><option value="paysage">A4 horizontal</option><option value="hauteur50">Hauteur 50%</option>  </select>');$("#fenetre > div:last").show();if($("#texte").val().length)$("#texte").attr("data-auto",0);$("#doc").on("change keyup",function(e){if(e.which==13)$("#fenetre a.icon-ok").click();var texte=$("#doc option:selected").text();if($("#texte").attr("data-auto")==1)$("#texte").val(this.value>0?texte.substr(0,texte.lastIndexOf("(")-1):"---");if("pdfjpgpegpng".indexOf(texte.slice(-4,-1))>-1)$("#vue").change().parent().show();else{$("#vue, #largeur, #format").parent().hide();$("#vue").prop("checked",false)}majapercu()});$("#texte").on("change keypress",function(e){if(e.which==0)return;if(e.which==13)$("#fenetre a.icon-ok").click();if(this.value.length==0){$(this).data("auto",1);$("#doc").change()}else{$(this).data("auto",0);majapercu()}});$("#vue").on("change",function(){if($("#vue").is(":checked")){if($("#doc option:selected").text().slice(-4,-1)=="pdf"){$("#largeur, #format").parent().show();$("#texte").parent().hide()}else if("jpgpegpng".indexOf($("#doc option:selected").text().slice(-4,-1))>-1){$("#largeur").parent().show();$("#format, #texte").parent().hide()}}else{$("#texte").parent().show();$("#largeur, #format").parent().hide()}majapercu()});$("#format").on("change keyup",function(e){if(e.which==13)$("#fenetre a.icon-ok").click();majapercu()});$("#largeur").on("keydown",function(e){if(e.which==38)++this.value;else if(e.which==40)--this.value}).on("change keyup",function(e){if(e.which==0)return;if(e.which==13)$("#fenetre a.icon-ok").click();if(this.value!=$(this).data("valeur")){$(this).data("valeur",this.value);majapercu()}}).attr("data-valeur",100);$("#rep").on("change",function(){$("#doc").html(data.docs[this.value]).change()});$("#mat").on("change",function(){$("#rep").html(data.reps[this.value]).change()}).focus().change();$("#fenetre a.icon-ok").on("click",function(){if($("#doc").val()){if($("#vue").is(":checked")&&"pdfjpgpegpng".indexOf($("#doc option:selected").text().slice(-4,-1))>-1)insert(el,$("#apercu").html(),"","");else insert(el,'<a href="download?id='+$("#doc").val()+'">',"</a>",$("#texte").val());$("#fenetre,#fenetre_fond").remove()}});$("#mat option").each(function(){if($("body").attr("data-matiere")==this.value)$("#mat").val(this.value).change()})};if("mats"in data)affichedocs(data)})}function insertion_lien2(el){popup('<a class="icon-ok" title="Valider"></a><h3>Insertion d\'un lien</h3>  <p class="ligne"><label for="texte">Texte visible&nbsp;: </label><input type="text" id="texte" value="'+marqueselection(el)+'" size="80"></p>  <p class="ligne"><label for="url">Adresse&nbsp;: </label><input type="text" id="url" value="http://" size="80"></p>  <hr><h3>Aperçu</h3><div id="apercu" style="text-align:center;"></div>',true);$("#fenetre input").on("click keyup",function(){$("#apercu").html($("#texte").val().length?'<a onclick="return false;" href="'+$("#url").val()+'">'+$("#texte").val()+"</a>":"[Écrivez un texte visible]")}).on("keypress",function(e){if(e.which==13)$("#fenetre a.icon-ok").click()}).first().keyup().focus();$("#fenetre a.icon-ok").on("click",function(){insert(el,'<a href="'+$("#url").val()+'">',"</a>",$("#texte").val());$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_tex(el){var chargement=typeof MathJax=="undefined"?'<script type="text/javascript" src="/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script><script type="text/x-mathjax-config">MathJax.Hub.Config({tex2jax:{inlineMath:[["$","$"],["\\\\(","\\\\)"]]}});</script>':"";var sel=marqueselection(el);var type="t1";if(sel.length)switch(sel.substring(0,2)){case"\\[":case"$$":type="t2";case"\\(":sel=sel.substring(2,sel.length-2);break;default:sel=sel.trim("$")}popup(chargement+'<a class="icon-montre" title="Mettre à jour l\'aperçu"></a><a class="icon-ok" title="Valider"></a><h3>Insertion de formules LaTeX</h3>  <p>Vous pouvez ci-dessous entrer et modifier une formule LaTeX. L\'aperçu présent en bas sera mis à jour uniquement lorsque vous cliquez sur l\'icône <span class="icon-montre"></span>.</p>  <p class="ligne"><label for="t1">La formule est en ligne (pas de retour)</label><input type="radio" name="type" id="t1" value="1"></p>  <p class="ligne"><label for="t2">La formule est hors ligne (formule centrée)</label><input type="radio" name="type" id="t2" value="2"></p>  <textarea id="formule" rows="3">'+sel+'</textarea>  <hr><h3>Aperçu</h3><div id="apercu" style="text-align:center;">[Demandez l\'aperçu en cliquant sur l\'icône <span class="icon-montre"></span>]</div>',true);$("#"+type).prop("checked",true);$("#formule").focus();$("#fenetre a.icon-montre").on("click",function(){if($("#formule").val().length){$("#apercu").html($("#t1").is(":checked")?"$"+$("#formule").val()+"$":"\\["+$("#formule").val()+"\\]").css("text-align","left");MathJax.Hub.Queue(["Typeset",MathJax.Hub,"apercu"])}else $("#apercu").html("[Écrivez une formule]").css("text-align","center")});$("#fenetre a.icon-ok").on("click",function(){if($("#t1").is(":checked"))insert(el,"$","$",$("#formule").val());else insert(el,"\\[","\\]",$("#formule").val());$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme,#fenetre_fond").on("click",function(){marqueselection(el,true)})}function insertion_par1(el){insert(el,"<p>","</p>")}function insertion_par2(el){insert(el,"<div class='note'>","</div>")}function insertion_par3(el){insert(el,"<div class='annonce'>","</div>")}function insertion_retour(el){insert(el,"<br>","")}function insertion_gras(el){insert(el,"<strong>","</strong>")}function insertion_italique(el){insert(el,"<em>","</em>")}function insertion_souligne(el){insert(el,"<u>","</u>")}function insertion_exp(el){insert(el,"<sup>","</sup>")}function insertion_ind(el){insert(el,"<sub>","</sub>")}function aidetexte(){popup('<h3>Aide et explications</h3>  <p>Il y a deux modes d\'éditions possibles pour éditer un texte&nbsp;: le mode «&nbsp;balises visibles&nbsp;» et le mode «&nbsp;balises invisibles&nbsp;». Il est possible de passer de l\'un à l\'autre&nbsp;:</p>  <ul>    <li><span class="icon-source"></span> permet de passer en mode «&nbsp;balises visibles&nbsp;» (par défaut), où le texte à taper est le code HTML de l\'article. Ce mode est plus précis. Les boutons aux dessus aident à utiliser les bonnes balises.</li>    <li><span class="icon-nosource"></span> permet de passer en mode «&nbsp;balises invisibles&nbsp;», où le texte est tel qu\'il sera affiché sur la partie publique, et modifiable. Ce mode est moins précis, mais permet le copié-collé depuis une page web ou un document Word/LibreOffice.  </ul>  <p>Une fonction de nettoyage du code HTML, permettant d\'assurer une homogénéité et une qualité d\'affichage optimales, est lancée à chaque commutation entre les deux modes, à chaque clic sur un des boutons disponibles, à chaque copie/coupe de texte et à chaque passage à la ligne.</p>  <p>En HTML, toutes les mises en formes sont réalisées par un encadrement de texte entre deux balises&nbsp;: &lt;h3&gt; et &lt;/h3&gt; pour un gros titre, &lt;p&gt; et &lt;/p&gt; pour un paragraphe. Le retour à la ligne simple, qui ne doit exister que très rarement, est une balise simple &lt;br&gt;. Mais les boutons disponibles sont là pour vous permettre de réaliser le formattage que vous souhaitez&nbsp;:</p>  <ul>    <li><span class="icon-titres"></span>&nbsp;: différentes tailles de titres (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-par1"></span>&nbsp;: paragraphe classique, qui doit obligatoirement encadrer au minimum chaque ligne de texte. Apparaît automatiquement au passage à la ligne si on l\'oublie.</li>    <li><span class="icon-par2"></span>&nbsp;: paragraphe important, écrit en rouge</li>    <li><span class="icon-par3"></span>&nbsp;: paragraphe très important, écrit en rouge et encadré</li>    <li><span class="icon-retour"></span>&nbsp;: retour à la ligne. Identique à un appui sur Entrée, et souvent inutile.</li>    <li><span class="icon-gras"></span>&nbsp;: mise en gras du texte entre les balises</li>    <li><span class="icon-italique"></span>&nbsp;: mise en italique du texte entre les balises</li>    <li><span class="icon-souligne"></span>&nbsp;: soulignement du texte entre les balises</li>    <li><span class="icon-omega"></span>&nbsp;: lettres grecques (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-sigma"></span>&nbsp;: symboles mathématiques (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-exp"></span>&nbsp;: mise en exposant du texte entre les balises</li>    <li><span class="icon-ind"></span>&nbsp;: mise en indice du texte entre les balises</li>    <li><span class="icon-ol"></span>&nbsp;: liste numérotée. Une fenêtre supplémentaire permet de choisir le type (1,A,a,I,i) et la première valeur. Les différentes lignes de la liste sont constituées par les balises &lt;li&gt; et &lt;/li&gt;</li>    <li><span class="icon-ul"></span>&nbsp;: liste à puces. Les différentes lignes de la liste sont constituées par les balises &lt;li&gt; et &lt;/li&gt;</li>    <li><span class="icon-lien1"></span>&nbsp;: lien d\'un document disponible ici (fenêtre supplémentaire pour choisir)</li>    <li><span class="icon-lien2"></span>&nbsp;: lien vers un autre site web (fenêtre supplémentaire pour entre l\'adresse)</li>    <li><span class="icon-tex"></span>&nbsp;: insertion de code LaTeX (fenêtre supplémentaire pour le taper)</li>  </ul>  <p class="tex2jax_ignore">Il est possible d\'insérer du code en LaTeX, sur une ligne séparée (balises \\[...\\] ou balises $$...$$) ou au sein d\'une phrase (balises $...$ ou balises \\(...\\)). Il faut ensuite taper du code en LaTeX à l\'intérieur. La prévisualisation est réalisée en direct.</p>',false)
+}function echange(el1,el2){if(el1.length&&el2.length){$("article").css("position","relative");el1.css("opacity",.3);el2.css("opacity",.3);el2.animate({top:el1.position().top-el2.position().top},1e3);el1.animate({top:(el2.outerHeight(true)+el2.outerHeight())/2},1e3,function(){el1.css("opacity",1);el2.css("opacity",1);el1.insertAfter(el2);el1.css({position:"static",top:0});el2.css({position:"static",top:0})})}}function cache(el){var prop=el.parent().attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{cache:1,action:prop[0],id:prop[1]},dataType:"json",el:el,fonction:function(el){el.parent().addClass("cache");el.removeClass("icon-cache").addClass("icon-montre").off("click").on("click",function(){montre($(this))}).attr("title","Montrer à nouveau")}})}function montre(el){var prop=el.parent().attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{montre:1,action:prop[0],id:prop[1]},dataType:"json",el:el,fonction:function(el){el.parent().removeClass("cache");el.removeClass("icon-montre").addClass("icon-cache").off("click").on("click",function(){cache($(this))}).attr("title","Cacher à nouveau")}})}function monte(el){var parent=el.parent();var prop=parent.attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{monte:1,action:prop[0],id:prop[1]},dataType:"json",el:parent,fonction:function(el){if(!el.prev().prev().is("article")){el.children(".icon-monte").hide(1e3);el.prev().children(".icon-monte").show(1e3)}if(!el.next().is("article")){el.children(".icon-descend").show(1e3);el.prev().children(".icon-descend").hide(1e3)}echange(el.prev(),el)}})}function descend(el){var parent=el.parent();var prop=parent.attr("data-id").split("|");$.ajax({url:"ajax.php",method:"post",data:{descend:1,action:prop[0],id:prop[1]},dataType:"json",el:parent,fonction:function(el){if(!el.prev().is("article")){el.children(".icon-monte").show(1e3);el.next().children(".icon-monte").hide(1e3)}if(!el.next().next().is("article")){el.children(".icon-descend").hide(1e3);el.next().children(".icon-descend").show(1e3)}echange(el,el.next())}})}function supprime(el){var parent=el.parent();var prop=parent.data("id").split("|");var item="un élément";switch(prop[0]){case"infos":item="une information";break;case"pages":item="la matière <em>"+$("h3",parent).text()+"</em>. Les informations qui y sont écrites seront aussi supprimées";break;case"reps":item="le répertoire <em>"+$(".nom",parent).map(function(){return this.textContent||$(this).find("input").val()}).get(0)+"</em>. <strong>Tous les sous-répertoires et documents qui s'y trouvent seront aussi supprimés</strong>";break;case"docs":item="le document <em>"+$(".nom",parent).map(function(){return this.textContent||$(this).find("input").val()}).get(0)+"</em>";break;case"colles":item="le programme de colle de la "+$(".edition",parent).text().toLowerCase();break;case"cdt-elems":item="un élément du cahier de texte";break;case"cdt-types":item="le type de séances <em>"+$("h3",parent).text()+"</em>. <strong>Les éléments du cahier de texte associés à ce type seront aussi supprimés</strong>";break;case"cdt-raccourcis":item="le raccourci de séance <em>"+$("h3",parent).text()+"</em>. Aucun élément du cahier de texte ne sera supprimé";break;case"notes":parent=parent.parent();item="une colle ou séance sans note du <em>"+$("td:first",parent).text()+"</em>, d'une durée de "+$("td:eq(3)",parent).text()+". Toutes les notes de cette colle seront supprimées";break;case"matieres":item="la matière <em>"+$("h3",parent).text()+"</em>. <p class=\"note\"><strong>ATTENTION&nbsp;: Les programmes de colles, le cahier de texte et les notes correspondantes seront toutes automatiquement supprimées.</strong></p> <p>Les répertoires, les documents, les pages d'informations spécifiques et les éléments de l'agenda associés à la matière seront conservés mais ne seront plus associés à une matière&nbsp;: ils seront désormais visibles dans le contexte «&nbsp;général&nbsp;».<br><strong>Si vous souhaitez simplement réinitialiser la matière, ce n'est pas la bonne méthode</strong>&nbsp;: vous devriez pouvoir faire ce que vous souhaitez avec les possibilités de cette page";break;case"groupes":item="le groupe <em>"+($(".editable",parent).text()||$("input:first",parent).val())+"</em>. Les utilisateurs concernés ne seront pas supprimés";break;case"agenda-elems":item="un événement de l'agenda";break;case"agenda-types":item="le type d'événement <em>"+$("h3",parent).text()+"</em>. <strong>Les événements de l'agenda associés à ce type seront aussi supprimés</strong>";break}confirmation("Vous allez supprimer XXX.<br>Cette opération n'est pas annulable.".replace("XXX",item),this,function(el){$.ajax({url:"ajax.php",method:"post",data:{supprime:1,action:prop[0],id:prop[1]},dataType:"json",el:parent,fonction:function(el){if(prop[0].match(/^(agenda-elems|colles)$/))location.reload(true);else el.remove()}})})}function lock(el){var parent=el.parent();var prop=parent.data("id").split("|");var protection=el.data("val");popup('<a class="icon-ok" title="Valider ce choix"></a><h3>Accès à l\'information</h3><table id="selmult">  <tr class="categorie"><td>Accès public</td><td><input value="0" type="checkbox"></td></tr>  <tr class="categorie"><td>Utilisateurs identifiés</td><td><input value="6" type="checkbox"></td></tr>  <tr class="element"><td>Invités</td><td><input value="1" type="checkbox"></td></tr>  <tr class="element"><td>Élèves</td><td><input value="2" type="checkbox"></td></tr>  <tr class="element"><td>Colleurs</td><td><input value="3" type="checkbox"></td></tr>  <tr class="element"><td>Lycée</td><td><input value="4" type="checkbox"></td></tr>  <tr class="element"><td>Professeurs</td><td><input value="5" type="checkbox"></td></tr>  <tr class="categorie"><td>Information invisible</td><td><input value="32" type="checkbox"></td></tr>  </tbody></table>',true);var f=$("#fenetre");if(protection==0||protection==32)$('input[value="'+protection+'"]',f).prop("checked",true).change();else{$("input[value=6]",f).prop("checked",true).change();for(var a=1;a<6;a++)if((protection-1>>a-1&1)==0)$('input[value="'+a+'"]',f).prop("checked",true).change()}var f=$("#fenetre");$("input[value=0],input[value=6],input[value=32]",f).parent().parent().addClass("categorie");$("tr:not(.categorie)",f).addClass("element");$("input",f).on("click",function(){if(this.value==0||this.value==32)$(this).parent().parent().siblings().find("input[type=checkbox]").prop("checked",false).change();else{$("input[value=0],input[value=32]",f).prop("checked",false).change();$("input[value=6]",f).prop("checked",true).change();if(this.value==6)$("tr:not(.categorie) input",f).prop("checked",true).change()}});$("tr",f).on("click",function(e){if(!$(e.target).is("input"))$(this).find("input").click()});$("input",f).on("change",function(){$(this).parent().parent().removeClass("sel");if(this.checked)$(this).parent().parent().addClass("sel")});$(".icon-ok",f).on("click",function(){if($('input[value="32"]',f).prop("checked"))var val=32;else if($('input[value="0"]',f).prop("checked"))var val=0;else var val=32-$("input:checked:not([value=6])",f).map(function(){return this.value|0}).get().reduce(function(acc,v){return acc+Math.pow(2,v-1)},0);el.data("val",val);$.ajax({url:"ajax.php",method:"post",data:{action:prop[0],id:prop[1],champ:"protection",val:val},dataType:"json",el:parent,fonction:function(el){location.reload(true)}})})}function ajoutecolle(el){var article=el.parent();el.before('<a class="icon-annule" title="Annuler"></a><a class="icon-ok" title="Valider"></a>');el.next().addBack().hide();var form=$("<form></form>").appendTo(article).html($("#form-ajoutecolle").html());$("textarea",form).on("change",function(e){$("body").data("nepassortir",true);$(this).off(e)});$("textarea",form).textareahtml();$("input",form).attr("id","cache");$(".icon-annule",article).on("click",function(){$("form,.icon-annule,.icon-ok",article).remove();el.next().addBack().show()});$("a.icon-ok",article).on("click",function(){$("textarea",form).each(function(){this.value=nettoie($(this).is(":visible")?this.value:$(this).next().html())});var id=article.data("id").split("|")[1];$.ajax({url:"ajax.php",method:"post",data:form.serialize()+"&action=ajout-colle&id="+id,dataType:"json",el:article,fonction:function(el){var texte=$("textarea",el).val();var cache=$("input",el).is(":checked");if(cache)el.addClass("cache");el.data("id","colles|"+id);$(".icon-aide",el).nextAll().remove();$(".icon-aide",el).after((cache?'<a class="icon-montre" title="Afficher le programme de colles sur la partie publique"></a>':'<a class="icon-cache" title="Rendre invisible le programme de colles sur la partie publique"></a>')+'<a class="icon-supprime" title="Supprimer ce programme de colles"></a><div class="editable edithtml" data-id="colles|texte|'+id+'" placeholder="Texte du programme de colles">'+texte+"</div>");$("a.icon-cache,a.icon-montre,a.icon-supprime",el).on("click",function(){window[this.className.substring(5)]($(this))});$(".editable",el).editinplace()}})});$("input,select",form).on("keypress",function(e){if(e.which==13){e.preventDefault();$("a.icon-ok",article).click()}})}function valide(){var data="";if($("#planning").length)data="action=planning&"+$("form").serialize();else{var id=$(this).parent().attr("data-id").split("|");data="action="+id[0]+"&id="+id[1]+"&"+$(this).nextAll("form").serialize()}if(data.length)$.ajax({url:"ajax.php",method:"post",data:data,dataType:"json",el:this,fonction:function(el){if(el.classList[1]!="noreload")location.reload(true)}}).done(function(data){if(data["etat"]=="confirm_mail"){$('[data-id="prefsperso|3"] p:first').html(data["message"]).addClass("annonce");$('[data-id="prefsperso|3"] p:hidden').show().children("input").attr("disabled",false)}});else affiche("<p>Aucune donnée envoyée.</p>","nok")}function formulaire(){var idform=this.className.split(" ")[0].substring(5);var action=$("#form-"+idform).data("action");$("#epingle").remove();var article=$('<article id="epingle"><a class="icon-ferme" title="Fermer"></a>  <a class="icon-aide" title="Aide pour ce formulaire"></a>  <a class="icon-ok" title="Valider"></a></article>').insertBefore($("article,#calendrier,#parentsdoc+*").first());var form=$("<form></form>").appendTo(article).html($("#form-"+idform).html());$("textarea",form).on("change",function(e){$("body").data("nepassortir",true);$(this).off(e)});$(".edithtml",form).textareahtml();$("input[name], select[name]:not([multiple])",form).attr("id",function(){return this.getAttribute("name")});switch(action){case"reps":$(this).init_reps();break;case"ajout-rep":form.append('<input type="hidden" name="parent" value="'+$(this).parent().data("id").split("|")[1]+'">');break;case"docs":case"ajout-doc":$(this).init_docs(action);break;case"cdt-elems":form.init_cdt_boutons();break;case"ajout-cdt-raccourci":form.init_cdt_raccourcis();break;case"notes":case"ajout-notes":$(this).init_notes(action);break;case"agenda-elems":$(this).init_evenements();break;case"ajout-agenda-types":$('[name="couleur"]',form).colpick();break;case"deplcolle":$("#ancien,#nouveau").each(function(){$(this).datetimepicker({format:"d/m/Y Ghi",timepicker:true})});break;case"ajout-utilisateurs":form.init_ajout_utilisateurs();break;case"ajout-groupe":$(".usergrp span",form).on("click",utilisateursgroupe);break}$("select[multiple]",form).each(selmult);$("#epingle .icon-ferme").on("click",function(){$("#epingle").remove()});$("#epingle a.icon-aide").on("click",function(){popup($("#aide-"+idform).html(),false)});$("#epingle a.icon-ok").on("click",function(){$(".edithtml",form).each(function(){this.value=nettoie($(this).is(":visible")?this.value:$(this).next().html())});if(action=="notes"||action=="ajout-notes")$("#epingle select:not(:visible)").val("x");$.ajax({url:"ajax.php",method:"post",data:form.serialize()+"&action="+action,dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$("input,select",form).on("keypress",function(e){if(e.which==13){e.preventDefault();$("#epingle a.icon-ok").click()}})}$.fn.init_reps=function(){var el=$(this);var form=$("#epingle form");var sel=$("select[multiple]",form);var id=el.parent().data("id").split("|")[1];var donnees=el.parent().data("donnees").split("|");var protection=donnees[2];var nom=el.siblings(".nom").text().split(/\/\s/).pop()||el.parent().find("input").val();$("em",form).text(nom);if(protection==0||protection==32)sel.val(protection);else{sel.val(6);for(var a=1;a<6;a++)if((protection-1>>a-1&1)==0)$('option[value="'+a+'"]',sel).prop("selected",true)}if(donnees[0]==0)$("#nom,#parent,#menu",form).parent().remove();else{$("#nom",form).val(nom);if(donnees[1]=="1")$("#menu",form).prop("checked",true);$('[data-parents*=",'+id+',"]',form).prop("disabled",true)}form.append('<input type="hidden" name="id" value="'+id+'">');$('input[type="button"]',form).on("click",function(){var contexte=$(this).parent().find("em").text();confirmation("Vous allez vider le répertoire <em>"+contexte+"</em>. Cela supprimera définitivement l'ensemble de ses sous-répertoires et des documents qu'ils contiennent.<br>Cette opération n'est pas annulable.",this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"reps",id:id,vide:1},dataType:"json",el:"",fonction:function(el){location.reload(true)}})})})};$.fn.init_docs=function(action){var el=$(this);var form=$("#epingle form");var nom=el.siblings(".nom").text().split(/\/\s/).pop()||el.parent().find("input").val();$("em",form).text(nom);var id=el.parent().data("id").split("|")[1];if(action=="docs"){var protection=el.parent().data("protection");form.append('<input type="hidden" name="id" value="'+id+'">');$("#nom",form).val(nom)}else{var protection=el.parent().data("donnees").split("|")[2];$("#fichier",form).on("change",function(){if(!$("#nom",form).val().length){var f=this.value;$("#nom",form).val(f.substring(f.lastIndexOf("\\")+1,f.lastIndexOf("."))||f)}});form.append('<input type="hidden" name="parent" value="'+id+'">')}var sel=$("select[multiple]",form);if(protection==0||protection==32)sel.val(protection);else{sel.val(6);for(var a=1;a<6;a++)if((protection-1>>a-1&1)==0)$('option[value="'+a+'"]',sel).prop("selected",true)}form.append('<input type="hidden" name="action" value="'+action+'">');$("#epingle a.icon-ok").addClass("icon-envoidoc").removeClass("icon-ok").on("click",function(){$.ajax({url:"docs.php",method:"post",data:"connexion=1",dataType:"json",el:"",fonction:function(el){if($("#fichier")[0].files.length>0){window.clearTimeout(extinction);$("#log").html("Envoi du document. Cela peut prendre du temps...")}var data=new FormData(form[0]);$.ajax({url:"ajax.php",method:"post",data:data,dataType:"json",contentType:false,processData:false,el:"",fonction:function(el){location.reload(true)}})}})})};$.fn.init_cdt_boutons=function(){var form=this;$("#jour,#pour").datetimepicker({format:"d/m/Y",timepicker:false});$("#h_debut").datetimepicker({format:"Ghi",datepicker:false,onClose:function(t,input){$("#h_fin").val(function(i,v){return v||(input.val().length?parseInt(input.val().slice(0,-3))+2+input.val().slice(-3):"")})}});$("#h_fin").datetimepicker({format:"Ghi",datepicker:false});var zero=function(n){return String(n).length==1?"0"+n:String(n)};$("#raccourci").on("change keyup",function(){var valeurs=raccourcis[this.value];for(var cle in valeurs){if(cle=="jour"){var t=new Date;var j=parseInt(valeurs["jour"]);t.setDate(j>t.getDay()?t.getDate()-t.getDay()-7+j:t.getDate()-t.getDay()+j);$("#jour").val(zero(t.getDate())+"/"+zero(t.getMonth()+1)+"/"+t.getFullYear())}else $("#"+cle).val(valeurs[cle])}$(this).data("modif",1);$("#tid").change()}).data("modif",0);$("#tid").on("change keyup",function(){switch(parseInt(seances[this.value])){case 0:$("#h_debut,#demigroupe").parent().show();$("#h_fin,#pour").parent().hide();break;case 1:$("#h_debut,#h_fin,#demigroupe").parent().show();$("#pour").parent().hide();break;case 2:$("#h_debut,#h_fin").parent().hide();$("#pour,#demigroupe").parent().show();break;case 3:$("#h_debut,#h_fin,#pour").parent().hide();$("#demigroupe").parent().show();break;default:$("#h_debut,#h_fin,#pour,#demigroupe").parent().hide()}$("#jour").change()});$("input,#demigroupe",form).on("change keyup",function(){if($("#raccourci").data("modif")==0)$("#raccourci").val(0);else $("#raccourci").data("modif",0)});$("input,select",form).on("keypress",function(e){if(e.which==13)$("a.icon-ok",el).click()});$("select:first",form).focus();$("#tid").change()};$.fn.init_cdt_raccourcis=function(){this.each(function(){var form=$(this);$('[id^="h_d"]',form).datetimepicker({format:"Ghi",datepicker:false,onClose:function(t,input){$('[id^="h_f"]',form).val(function(i,v){return v||(input.val().length?parseInt(input.val().slice(0,-3))+2+input.val().slice(-3):"")})}});$('[id^="h_fin"]').datetimepicker({format:"Ghi",datepicker:false});$('[id^="type"]',form).on("change keyup",function(){switch(parseInt(seances[this.value])){case 0:$('[id^="h_d"],[id^="dem"]',form).parent().show();$('[id^="h_f"]',form).parent().hide();break;case 1:$('[id^="h_d"],[id^="h_f"],[id^="dem"]',form).parent().show();break;case 2:case 3:$('[id^="h_d"],[id^="h_f"]',form).parent().hide();$('[id^="dem"]',form).parent().show();break;default:$('[id^="h_d"],[id^="h_f"],[id^="dem"]',form).parent().hide()}}).change();$("input,select",form).on("keypress",function(e){if(e.which==13)$("a.icon-ok",form).click()})})};$.fn.init_notes=function(action){var el=$(this);var form=$("#epingle form").append($("#form-notes").html());var table=$("table",form);$("input, select",form).attr("id",function(){return this.getAttribute("name")});$("tr[data-id]",table).append("<td>"+$("div",form).html()+"</td>");$("select",table).attr("name",function(){return"e"+$(this).parent().parent().data("id")});$("div",form).remove();if($("input:checkbox",table).length){$("tr[data-id]",form).hide();$("input:checkbox",table).on("change",function(){if($("input:checkbox:last",table).prop("checked"))return $("tr[data-id]",form).show();var ids=$("input:checked",table).map(function(){return this.value.split(",")}).get().concat();$("tr[data-id]:not(.orig)",table).hide();for(var i=0;i<ids.length;i++)$('tr[data-id="'+ids[i]+'"]',form).show()})}function marque_dejanotes(sid){if(sid==0)return true;var dn=dejanotesautres[sid].split(",");for(var i=0;i<dn.length;i++)$('tr[data-id="'+dn[i]+'"]',form).addClass("dejanote").find("td:eq(0)").text(function(){return this.textContent+" (noté par un autre colleur)"});var dn=dejanotesperso[sid].split(",");for(var i=0;i<dn.length;i++)$('tr[data-id="'+dn[i]+'"]:not(.orig)',form).addClass("dejanote").find("td:eq(0)").text(function(){return this.textContent+" (déjà noté par vous-même)"});$(".dejanote select").prop("disabled",true).val("x")}$("#jour").datetimepicker({format:"d/m/Y",timepicker:false,onShow:function(){if($("#td").is(":checked"))this.setOptions({minDate:$("#form-ajoute option:eq(1)").data("date"),maxDate:new Date(new Date($("#form-ajoute option:last").data("date").replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x})).getTime()+6*864e5)});else this.setOptions({minDate:debut||$("#sid option:selected").data("date"),maxDate:new Date(new Date((fin||$("#sid option:selected").next().data("date")).replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x})).getTime()-864e5)})}});$("#heure").datetimepicker({format:"Ghi",datepicker:false,defaultTime:"15h30"});$("#duree").datetimepicker({format:"Ghi",datepicker:false,defaultTime:"0h00",step:10}).on("change",function(){$(this).removeClass("auto")});$("select",table).on("change keyup",function(){var nb=$("table select:visible",form).filter(function(){return this.value!="x"}).length;var duree=nb*(dureecolle||20);if($("#duree").is(".auto")||duree>$("#duree").val().replace(/^(\d*)h(\d*)$/,function(tout,x,y){return 60*(x|0)+(y|0)}))$("#duree").val((duree/60|0)+"h"+(duree%60||"")).addClass("auto")});if(action=="ajout-notes"){$("#sid").on("change keyup",function(){$(".dejanote td:first-child").text(function(){return this.textContent.replace(" (noté par un autre colleur)","").replace(" (déjà noté par vous-même)","")});$(".dejanote").removeClass("dejanote").find("select").prop("disabled",false);marque_dejanotes($("#sid").val());var jour=new Date($("#jour").val().replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));var debut=new Date($("#sid option:selected").data("date").replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));var fin=new Date($("#sid option:selected").next().data("date").replace(/(.{2})\/(.{2})\/(.{4})/,function(tout,x,y,z){return z+"-"+y+"-"+x}));if(jour<debut||jour>fin){debut=debut.toJSON();$("#jour").val(debut.substr(8,2)+"/"+debut.substr(5,2)+"/"+debut.substr(0,4))}}).change();$("#td").on("change keyup",function(){if(this.checked){$("#sid").parent().hide();$("#description").parent().show();table.hide()}else{$("#sid").parent().show();$("#description").parent().hide();table.show()}});$("#description").parent().hide()}else{var tr=el.parent().parent();if(el.data("sid")){$("#description, #td").parent().remove();var sid=el.data("sid");var debut=$('#form-ajoute option[value="'+sid+'"]').data("date");var fin=$('#form-ajoute option[value="'+sid+'"]').next().data("date");var eleves=el.data("eleves").split("|");var notes=el.data("notes").split("|");for(var i=0;i<eleves.length;i++)$('tr[data-id="'+eleves[i]+'"]',form).addClass("orig").show().find("select").val(notes[i]).on("change",function(){$(this).parent().parent().removeClass("orig")});$("h3",form).text("Modifier des notes - semaine du "+$('select[name="sid"] option[value="'+sid+'"]').text().split(" ").slice(0,3).join(" "));if(el.next().length)marque_dejanotes(sid);else{$('tr:not(.orig), .orig option[value="x"]',table).remove();$("#duree").prop("disabled",true);form.append("<p>Cette colle a déjà été relevée&nbsp;: il est impossible de modifier quels élèves ont été interrogés ou la durée de la colle. Vous pouvez corriger la date et l'heure (dans la limite de la semaine enregistrée) ou les notes que vous avez mises vous pouvez mettre une note à un élève initialement absent qui a rattrapé sa colle.</p>")}}else{table.remove();$("#td").prop("checked",true).prop("disabled",true);$("#description").val(el.parent().prev().prev().prev().text());$("h3",form).text("Modifier la séance de TD sans note");if(el.next().length==0){$("#duree").prop("disabled",true);form.append("<p>Cette séance a déjà été relevée&nbsp;: il est impossible de modifier sa durée. Vous pouvez corriger la date, l'heure ou la description.</p>")}}$("#id").val(el.parent().data("id").split("|")[1]);$("#jour").val($("td:eq(0)",tr).text().replace(/(.{6})(.{2})/,function(tout,x,y){return x+"20"+y}));$("#heure").val($("td:eq(1)",tr).text().replace("-",""));$("#duree").val($("td:eq(3)",tr).text().replace(/.*m/,function(s){return"0h"+s.slice(0,-1)}))}};$.fn.init_ajout_utilisateurs=function(){$("#autorisation,#saisie").on("change",function(){var f=$("#epingle form");var a=$("#autorisation",f).val();if(a==0){$(".affichesiinvite,.affichesiinvitation,.affichesimotdepasse",f).hide(0);$("textarea",f).prop("disabled",true).attr("placeholder","Zone de saisie des utilisateurs\nSélectionnez d'abord un type d'utilisateur")}else{var inv=a==1;var mdp=$("#saisie",f).val()==2;$("#saisie",f).parent().toggle(!inv);$(".affichesiinvite",f).toggle(inv);$(".affichesiinvitation",f).toggle(!inv&&!mdp);$(".affichesimotdepasse",f).toggle(!inv&&mdp);$("textarea",f).prop("disabled",false).attr("placeholder",function(){if(inv)return"identifiant_1,motdepasse_1\nidentifiant_2,motdepasse_2\nidentifiant_3,motdepasse_3\n...";else if(mdp)return"nom_1,prénom_1,motdepasse_1\nnom_2,prénom_2,motdepasse_2\nnom_3,prénom_3,motdepasse_3\n...";else return"nom_1,prénom_1,adresse_1\nnom_2,prénom_2,adresse_2\nnom_3,prénom_3,adresse_3\n..."})}}).change()};$.fn.init_evenements=function(){var el=$(this);var form=$("#epingle form");$("textarea",form).attr("id","texte");if(el.is(".modifevnmt")){var id=el.attr("id").substr(1);var valeurs=evenements[id];var cles=["type","matiere","debut","fin","texte"];for(var i=0;i<6;i++){$("#"+cles[i]).val(valeurs[cles[i]])}$("#id").val(id);$("#texte").change();$("#jours").prop("checked",valeurs["je"]);$('<a class="icon-supprime" title="Supprimer cette information"></a>').insertBefore($(".icon-ok")).on("click",function(){supprime($(this))}).parent().data("id","agenda-elems|"+id)}$("#debut").datetimepicker({onShow:function(){this.setOptions({maxDate:$("#fin").val()||false})},onClose:function(t,input){$("#fin").val(function(i,v){return v||input.val()})}});$("#fin").datetimepicker({onShow:function(){this.setOptions({minDate:$("#debut").val()||false})},onClose:function(t,input){$("#debut").val(function(i,v){return v||input.val()})}});$("#jours").on("change",function(){var v;if(this.checked){$("#debut,#fin").each(function(){v=this.value.split(" ");$(this).val(v[0]).attr("data-heure",v[1]).datetimepicker({format:"d/m/Y",timepicker:false})})}else{$("#debut,#fin").each(function(){if(this.hasAttribute("data-heure"))$(this).val(this.value+" "+$(this).attr("data-heure")).removeAttr("data-heure");$(this).datetimepicker({format:"d/m/Y Ghi",timepicker:true})})}}).change()};function selmult(){var sel=$(this);var isacces=this.getAttribute("name").indexOf("protection")+1?1:0;function majselect(sel){sel.prev().children().prop("selected",false).text(function(){var options=$(isacces?"option:selected:not([value=6])":"option:selected",sel);if(isacces&&options.length==5)return"Tout utilisateur identifié";if(options.length==0)return"Choisir ...";else return options.map(function(){return this.textContent}).get().join(", ")}).prop("selected",true)}$("<select id="+sel.prev().attr("for")+"><option selected hidden></option></select>").insertBefore(sel.hide(0)).attr("disabled",sel.attr("disabled")).on("mousedown",function(e){e.preventDefault();this.blur();popup('<a class="icon-ok" title="Valider ce choix"></a><h3>'+sel.prev().prev().text().replace(":","")+'</h3><table id="selmult">'+$("option",sel).map(function(){return"<tr"+(this.selected?' class="sel"':"")+"><td>"+this.textContent+'</td><td><input type="checkbox" '+(this.selected?"checked ":"")+'value="'+this.value+'"></td></tr>'}).get().join("")+"</table>",true);var f=$("#fenetre");if(isacces){$("input[value=0],input[value=6],input[value=32]",f).parent().parent().addClass("categorie");$("tr:not(.categorie)",f).addClass("element");$("input",f).on("click",function(){if(this.value==0||this.value==32)$(this).parent().parent().siblings().find("input[type=checkbox]").prop("checked",false).change();else{$("input[value=0],input[value=32]",f).prop("checked",false).change();$("input[value=6]",f).prop("checked",true).change();if(this.value==6)$("tr:not(.categorie) input",f).prop("checked",true).change()}})}else{$("#selmult",f).prepend('<tr class="categorie"><th></th><th><a class="icon-cocher"></a></th></tr>');$(".icon-cocher",f).on("click",cocher_utilisateurs)}$("tr",f).on("click",function(e){if(!$(e.target).is("input"))$(this).find("input").click()});$("input",f).on("change",function(){$(this).parent().parent().toggleClass("sel",this.checked)});$(".icon-ok",f).on("click",function(){sel.val($("input:checked",f).map(function(){return this.value}).get());majselect(sel);$("#fenetre, #fenetre_fond").remove()})});majselect(sel)}function cocher_utilisateurs(){$(this).toggleClass("icon-cocher icon-decocher").parent().parent().nextUntil(".categorie").find("input").prop("checked",$(this).hasClass("icon-decocher")).change()}function edite_utilisateur(){var id=$(this).parent().parent().data("id");$.ajax({url:"recup.php",method:"post",data:{action:"prefs",id:id},dataType:"json",afficheform:function(data){if("nom"in data){popup($("#form-edite").html(),true);var f=$("#fenetre");$("input[name]",f).attr("id",function(){return this.getAttribute("name")});if(data["valide"])$("#comptedesactive, #demande, #invitation",f).remove();else if(data["demande"])$("#compteactif, #comptedesactive, #invitation",f).remove();else if(data["invitation"])$("#compteactif, #comptedesactive, #demande",f).remove();else $("#compteactif, #demande, #invitation",f).remove();if(data["autorisation"]==1)$("#nom, #prenom, #mail1, #mail2",f).parent().remove();$("p:first",f).html(function(i,code){return code.replace("XXX",data["prenom"].length?"de <em>"+data["prenom"]+" "+data["nom"]+"</em>":"<em>"+data["login"]+"</em>").replace("YYY","<em>"+["Invité","Élève","Colleur","Lycée","Professeur"][data["autorisation"]-1]+"</em>")});$('input[type="text"],input[type="email"]',f).val(function(){return data[this.id]});$('input[type="checkbox"]',f).prop("checked",function(){return data[this.id]});if(!data["mailenvoi"])$('[name="mailexp"],[name="mailcopie"]',f).parent().remove();$("a.icon-ok",f).on("click",function(){$.ajax({url:"ajax.php",method:"post",data:"action=utilisateur&modif=prefs&id="+id+"&"+$("form",f).serialize(),dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$("input",f).on("keypress",function(e){if(e.which==13){e.preventDefault();$("a.icon-ok",f).click()}})}}})}function init_utilisateurs(){$(".icon-cocher").on("click",cocher_utilisateurs);$("td .icon-edite").on("click",edite_utilisateur);$("td .icon-desactive, td .icon-active, td .icon-supprutilisateur, td .icon-validutilisateur").on("click",modif_utilisateur);$("th .icon-desactive, th .icon-active, th .icon-supprutilisateur, th .icon-validutilisateur").on("click",modif_utilisateurs);$("td:not(.icones)").on("click",function(){$(this).parent().find("input").click()});$("#u input").on("change",function(){$(this).parent().parent().toggleClass("sel",this.checked)});function modif_utilisateur(){var question="";var nom=$(this).parent().siblings().first();var compte=nom.text().length?"de <em>"+nom.next().text()+" "+nom.text()+"</em>":"d'identifiant <em>"+nom.next().next().text()+"</em>";var categorie=$(this).parent().parent().prevUntil(".categorie").last().prev().text().split(" ")[0];switch(this.className.substring(5)){case"desactive":if(categorie=="Invités")question="Vous allez désactiver le compte invité "+compte+". Cela signifie que le compte ne sera pas supprimé mais sera non utilisable pour une connexion. Les associations éventuelles avec les matières seront conservées. Ce compte sera listé dans la partie inférieure du tableau.";else question="Vous allez désactiver le compte "+compte+". Cela signifie que le compte sera toujours visible pour les professeurs mais que l'utilisateur correspondant ne pourra plus se connecter. <strong>Les notes de colles éventuelles seront conservées. Les données associées au compte seront conservées.</strong><br> Les accès spécifiques éventuels pourront être rétablis en réactivant le compte.<br> Ce compte sera listé dans la partie inférieure du tableau.<br> Cette possibilité est particulièrement utile pour un élève ou un colleur parti en cours d'année et dont il faut conserver les notes de colles.";break;case"active":if(categorie=="Invités")question="Vous allez réactiver le compte invité "+compte+". La connexion sera à nouveau possible. Ce compte apparaîtra à nouveau dans la partie principale du tableau.";else question="Vous allez réactiver le compte "+compte+". Cela signifie que l'utilisateur correspondant pourra à nouveau se connecter. Il retrouvera son compte, ses notes de colles éventuelles, ses préférences, ses accès spécifiques éventuels, sans modification. Ce compte apparaîtra à nouveau dans la partie principale du tableau.";break;case"supprutilisateur":if(categorie=="Demandes")question="Vous allez supprimer la demande "+compte+". Cela signifie que cette demande ne conduira pas à une création de compte. Le demandeur ne sera pas prévenu de votre décision.<br> Une fois réalisée, cette opération est définitive, mais rien n'empêche le demandeur d'effectuer une nouvelle demande.<br> <strong>Si vous n'attendez plus de nouvelle demande de création de compte, il est certainement préférable de supprimer cette possibilité à l'aide du réglage accessible en cliquant sur l'icône <span class=\"icon-prefs\"></span> en haut à droite sur cette page</strong>";
+else if(categorie=="Invitations"){var textecolles=$(this).parent().prev().prev().text()=="Élève"?'<p class="note"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur ce compte seront supprimées. Cette suppression est définitive.</strong></p><p>':"<br>";question="Vous allez supprimer l'invitation "+compte+". Cela signifie que cette invitation ne sera plus valable et que si la personne invitée clique sur le lien reçu par courriel, une erreur apparaîtra devant elle."+textecolles+"<strong>L'invitation envoyée n'a pas de date de péremption&nbsp;: il est n'est pas normal de supprimer l'invitation pour la refaire, à moins de s'être trompé d'adresse électronique. Si la personne invitée vous dit ne pas réussir à s'identifier, proposez-lui de passer par le lien <em>Mot de passe oublié</em>.</strong><br> La personne invitée ne sera pas prévenue de votre décision."}else if(categorie=="Professeurs")question="Vous allez supprimer le compte professeur "+compte+'. <strong>Cela signifie que toutes les préférences de ce compte seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.<br> Les données des matières auxquelles il est associé sont indépendantes&nbsp;: elles ne seront pas supprimées.';else if(categorie=="Lycée")question="Vous allez supprimer le compte lycée "+compte+". Cela signifie que toutes les préférences de ce compte seront perdues.";else if(categorie=="Colleurs")question="Vous allez supprimer le compte colleur "+compte+'. <strong>Cela signifie que toutes les préférences de ce compte seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Élèves")question="Vous allez supprimer le compte élève "+compte+'. <strong>Cela signifie que toutes les données correspondant à ce compte seront perdues. Les groupes où il apparaît seront modifiés, les notes de colles éventuelles seront supprimées.</strong> <p class="note"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur ce compte seront supprimées. Cette suppression est définitive.<br> Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur du compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données de l\'utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Invités")question="Vous allez supprimer le compte invité "+compte+". Cela signifie que la connexion par ce compte ne sera plus possible.";else question="Vous allez supprimer le compte "+compte+" déjà désactivé. <strong>Cela signifie que toutes les données correspondant à ce compte seront perdues définitivement. Les groupes où il apparaît seront modifiés, les notes de colles éventuelles seront supprimées.</strong>";if(categorie!="Demandes")question=question+"<br>Une fois réalisée, cette opération est définitive.";break;case"validutilisateur":question="Vous allez valider la demande "+compte+". Son compte sera immédiatement actif et un courriel va immédiatement être envoyé pour le/la prévenir.<br> Il sera automatiquement associé à toutes les matières&nbsp;: <strong>pensez à aller supprimer les matières qui ne le concernent pas sur la page de gestion des associations utilisateurs-matières.</strong>"}confirmation(question,this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateur",modif:el.className.substring(5),id:$(el).parent().parent().data("id")},dataType:"json",el:"",fonction:function(){location.reload(true)}})})}function modif_utilisateurs(){var cases=$(this).parent().parent().nextUntil(".categorie").find(":checked");if(cases.length==0){affiche("<p>Aucune case n'est cochée, aucune action ne peut être réalisée.</p>","nok");return}var lignes=cases.parent().parent();var ids=lignes.map(function(){return $(this).data("id")}).get().join(",");var comptes=lignes.map(function(){var nom=$(this).children().first().text();return nom.length?"<em>"+$(this).children().eq(1).text()+" "+nom+"</em>":"<em>"+$(this).children().eq(2).text()+"</em>"}).get().join(", ");var pos=comptes.lastIndexOf(",");if(pos>0)comptes=comptes.substring(0,pos)+" et"+comptes.substring(pos+1);var question="";var categorie=$(this).parent().parent().prev().children().text().split(" ")[0];switch(this.className.substring(5)){case"desactive":if(categorie=="Invités")question="Vous allez désactiver les comptes invités "+comptes+". Cela signifie que ces compte ne seront pas supprimés mais seront non utilisables pour une connexion. Les associations éventuelles avec les matières seront conservées. Ces comptes seront listés dans la partie inférieure du tableau.";else question="Vous allez désactiver le compte "+compte+". Cela signifie que le compte sera toujours visible pour les professeurs mais que l'utilisateur correspondant ne pourra plus se connecter. <strong>Les notes de colles éventuelles seront conservées. Les données associées au compte seront conservées.</strong><br> Les accès spécifiques éventuels pourront être rétablis en réactivant le compte.<br> Ce compte sera listé dans la partie inférieure du tableau.<br> Cette possibilité est particulièrement utile pour un élève ou un colleur parti en cours d'année dont il faut conserver les notes de colles.";question="Vous allez désactiver les comptes de "+comptes+". Cela signifie que ces comptes seront toujours visibles pour les professeurs mais que les utilisateurs correspondant ne pourront plus se connecter. <strong>Les notes de colles éventuelles seront conservées. Les données associées aux comptes seront conservées.</strong><br> Les accès spécifiques éventuels pourront être rétablis en réactivant les comptes.<br> Ces comptes seront listés dans la partie inférieure du tableau.<br> Cette possibilité est particulièrement utile pour des élèves ou des colleurs partis en cours d'année et dont il faut conserver les notes de colles.";break;case"active":if(categorie=="Invités")question="Vous allez réactiver les comptes invité "+comptes+". La connexion sera à nouveau possible. Ces comptes apparaîtront à nouveau dans la partie principale du tableau.";else question="Vous allez réactiver les comptes de "+comptes+". Cela signifie que les utilisateurs correspondant pourront à nouveau se connecter. Ils retrouveront leur compte, leurs notes de colles éventuelles, leurs préférences, leurs accès spécifiques éventuels, sans modification. Ces comptes apparaîtront à nouveau dans la partie principale du tableau.";break;case"supprutilisateur":if(categorie=="Demandes")question="Vous allez supprimer les demandes de "+comptes+". Cela signifie que ces demandes ne conduiront pas à des créations de compte. Les demandeurs ne seront pas prévenus de votre décision.<br> Une fois réalisée, cette opération est définitive, mais rien n'empêche les demandeurs d'effectuer une nouvelle demande.<br> <strong>Si vous n'attendez plus de nouvelle demande de création de compte, il est certainement préférable de supprimer cette possibilité à l'aide du réglage accessible en cliquant sur l'icône <span class=\"icon-prefs\"></span> en haut à droite sur cette page</strong>";else if(categorie=="Invitations"){question="Vous allez supprimer les invitations de "+comptes+". Cela signifie que ces invitations ne seront plus valables et que si les personnes invitées cliquent sur le lien reçu par courriel, une erreur apparaîtra devant elles. <p class=\"note\"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur les comptes de types élèves seront supprimées. Ces suppressions sont définitives.</strong></p> <p><strong>Ces invitations envoyées n'ont pas de date de péremption&nbsp;: il n'est pas normal de supprimer une invitation pour la refaire, à moins de s'être trompé d'adresse électronique. Si une personne invitée vous dit ne pas réussir à s'identifier, proposez-lui de passer par le lien <em>Mot de passe oublié</em>.</strong><br> Les personnes invitées ne seront pas prévenues de votre décision."}else if(categorie=="Professeurs")question="Vous allez supprimer les comptes professeurs de "+comptes+'. <strong>Cela signifie que toutes les préférences de ces comptes seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.<br> Les données des matières auxquelles ces utilisateurs sont associés sont indépendantes&nbsp;: elles ne seront pas supprimées.';else if(categorie=="Lycée")question="Vous allez supprimer les comptes lycée de "+comptes+". Cela signifie que toutes les préférences de ces comptes seront perdues.";else if(categorie=="Colleurs")question="Vous allez supprimer les comptes colleurs de "+comptes+'. <strong>Cela signifie que toutes les préférences de ces comptes seront perdues, ainsi que les éventuelles notes de colles.</strong> <p class="note"><strong>Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Élèves")question="Vous allez supprimer les comptes élèves de "+comptes+'. <strong>Cela signifie que toutes les données correspondant à ces comptes seront perdues. Les groupes où ils apparaissent seront modifiés, les notes de colles éventuelles seront supprimées.</strong> <p class="note"><strong>ATTENTION : toutes les notes de colles qui ont déjà pu être déclarées sur ces compte seront supprimées. Cette suppression est définitive.<br> Supprimer un compte pour le recréer n\'est pas la bonne méthode pour réinitialiser un compte,</strong></p><p> par exemple si l\'utilisateur d\'un compte vous indique ne pas arriver à se connecter. Dans ce cas, proposez-lui de passer par le lien <em>Mot de passe oublié</em>. Vous pouvez modifier sur la <a href="utilisateurs">gestion des utilisateurs</a> les nom, prénom, identifiant de connexion et adresse électronique de chaque utilisateur.<br> Pour conserver les données d\'un utilisateur mais lui empêcher la connexion, vous pouvez désactiver le compte en cliquant sur <span class="icon-desactive"></span>.';else if(categorie=="Invités")question="Vous allez supprimer les comptes invités de "+comptes+". Cela signifie que la connexion par ces comptes ne sera plus possible.";else question="Vous allez supprimer les comptes de "+comptes+" déjà désactivés. <strong>Cela signifie que toutes les données correspondant à ces comptes seront perdues définitivement. Les groupes où ils apparaîssent seront modifiés, les notes de colles éventuelles seront supprimées. Dans le cas des comptes professeurs, les données des matières associées ne seront pas supprimées.</strong>";if(categorie!="Demandes")question=question+"<br>Une fois réalisée, cette opération est définitive.";break;case"validutilisateur":question="Vous allez valider les demandes de "+comptes+". Leurs comptes seront immédiatement actifs et un courriel va immédiatement leur être envoyé pour les prévenir.<br> Ils seront automatiquement associés à toutes les matières&nbsp;: <strong>pensez à aller supprimer les matières qui ne les concernent pas sur la page de gestion des associations utilisateurs-matières.</strong>"}confirmation(question,this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateurs",modif:el.className.substring(5),ids:ids},dataType:"json",el:"",fonction:function(){location.reload(true)}})})}}function init_utilisateurs_matieres(){$("tr:not(.categorie) td:not(:first-child,:last-child)").each(function(){var valeurs=this.textContent.split("|");this.innerHTML=valeurs[1]==1?'<a class="icon-ok" data-id="'+valeurs[0]+'" title="Supprimer l\'association à la matière"></a>':'<a class="icon-nok" data-id="'+valeurs[0]+'" title="Établir l\'association à la matière"></a>'});$("#umats a").on("click",association_um);$(".categorie [data-id]").on("click",association_ums).hide(0);$(".icon-cocher").on("click",cocher_utilisateurs).on("click",majicones);$('input[type="checkbox"]').on("click",majicones).on("change",function(){$(this).parent().parent().toggleClass("sel",this.checked)});$("td:first-child").on("click",function(){$(this).parent().find("input").click()});function majicones(){var tr=$(this).parent().parent();if(!tr.hasClass("categorie"))tr=tr.prevAll(".categorie").first();var cases=tr.nextUntil(".categorie").find(":checked");if(cases.length==0)$("[data-id]",tr).hide(0);else $("[data-id]",tr).each(function(){var avant=$(this).hasClass("icon-ok");var apres=cases.parent().prevAll().find('.icon-ok[data-id="'+this.getAttribute("data-id")+'"]').length<cases.length/2;if(avant!=apres)$(this).toggleClass("icon-ok icon-nok").attr("title",(apres?"Établir":"Supprimer")+" l'association à la matière de tous les cochés")}).show(0)}function association_um(){var val=$(this).hasClass("icon-ok");$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateur-matiere",id:$(this).parent().parent().data("id"),matiere:$(this).data("id"),val:1-val},dataType:"json",el:$(this),fonction:function(el){el.toggleClass("icon-ok icon-nok").attr("title",(val?"Établir":"Supprimer")+" l'association à la matière")}})}function association_ums(){var cases=$(this).parent().parent().nextUntil(".categorie").find(":checked");if(cases.length==0){affiche("<p>Aucune case n'est cochée, aucune action ne peut être réalisée.</p>","nok");return}var lignes=cases.parent().parent();var ids=lignes.map(function(){return $(this).data("id")}).get().join(",");var comptes=lignes.children(":first-of-type").map(function(){return $(this).text().split("(")[0].trim()}).get().join(", ");var pos=comptes.lastIndexOf(",");if(pos>0)comptes=comptes.substring(0,pos)+" et"+comptes.substring(pos+1);var val=$(this).hasClass("icon-ok");var mid=this.getAttribute("data-id");var question=val?"Vous allez établir l'association à la matière "+$("#m"+mid).text()+" pour les comptes de "+comptes+". Cela signifie que ces utilisateurs auront accès aux ressources liées à cette matière, en fonction de l'autorisation que vous avez fixée pour ces ressources.":"Vous allez supprimer l'association à la matière "+$("#m"+mid).text()+" pour les comptes de "+comptes+". Cela signifie que ces utilisateurs n'auront plus accès aux ressources liées à cette matière. Si des notes de colles ont été saisies, elles seront automatiquement et définitivement supprimées de la base.";confirmation(question,this,function(el){$.ajax({url:"ajax.php",method:"post",data:{action:"utilisateurs-matieres",ids:ids,matiere:mid,val:val|0},dataType:"json",el:"",fonction:function(el){location.reload(true)}})})}}function init_envoimails(){var t=$("#envoimails");$("td",t).each(function(){var valeurs=this.textContent.split("|");this.innerHTML=valeurs[1]==1?'<a class="icon-ok" data-id="'+valeurs[0]+'" title="Supprimer l\'autorisation d\'envoi"></a>':'<a class="icon-nok" data-id="'+valeurs[0]+'" title="Établir l\'autorisation d\'envoi"></a>'});$("td a",t).on("click",function(){var val=$(this).hasClass("icon-nok")|0;$.ajax({url:"ajax.php",method:"post",data:{action:"prefsglobales",mails:1,depuis:$(this).parent().parent().data("id"),vers:$(this).data("id"),val:val},dataType:"json",el:$(this),fonction:function(el){el.toggleClass("icon-ok icon-nok").attr("title",(val?"Établir":"Supprimer")+" l'autorisation d'envoi")}})});$("th span",t).on("click",function(){var val=$(this).hasClass("icon-ok");var ligne=$(this).parent().parent();$.ajax({url:"ajax.php",method:"post",data:{action:"prefsglobales",mails:1,depuis:ligne.data("id"),vers:0,val:val|0},dataType:"json",el:ligne,fonction:function(el){el.find("td a").toggleClass("icon-ok",val).toggleClass("icon-nok",!val).attr("title",(val?"Établir":"Supprimer")+" l'autorisation d'envoi")}})});$("#umails .icon-edite").on("click",edite_utilisateur)}function init_utilisateurs_groupes(){$('article input[type="checkbox"]').on("change",function(){$.ajax({url:"ajax.php",method:"post",data:{action:"groupes",champ:this.id.substr(0,5),id:this.id.substr(5),val:this.checked|0},dataType:"json",el:"",fonction:function(el){return true}})});$(".usergrp span").append('&nbsp;<a class="icon-edite" title="Éditer les utilisateurs de ce groupe"></a>').on("click",utilisateursgroupe)}function utilisateursgroupe(){popup($("#form-utilisateurs").html(),true);var f=$("#fenetre");var span=$(this);article=span.parent().parent();$("table",f).attr("id","ugrp");$("h3",f).append($(".editable",article).text()||$("input:first",article).val());$(".icon-deplie",f).on("click",plie);$(".icon-cocher",f).on("click",cocher_utilisateurs);$("tr:not(.categorie)",f).on("click",function(e){if(!$(e.target).is("input"))$(this).find("input").click()});$("input",f).on("change",function(){$(this).parent().parent().toggleClass("sel",this.checked)});var ids=span.data("uids");$("#u"+ids.replace(/,/g,",#u"),f).prop("checked",true).change();$(".icon-ok",f).on("click",function(){var ids=$("input:checked",f).map(function(){return this.id.replace("u","")}).get().join(",");var noms=$("input:checked",f).parent().prev().map(function(){return this.textContent.split("(")[0].trim()}).get().join(", ")||"[Personne]";if(article.is("div")){$("#uids",article).val(ids);span.data("uids",ids);span.html(noms+'&nbsp;<a class="icon-edite" title="Éditer les utilisateurs de ce groupe"></a>');$("#fenetre, #fenetre_fond").remove()}else $.ajax({url:"ajax.php",method:"post",data:{action:"groupes",champ:"utilisateurs",id:article.data("id").split("|")[1],uids:ids},dataType:"json",el:span,fonction:function(el){el.data("uids",ids);el.html(noms+'&nbsp;<a class="icon-edite" title="Éditer les utilisateurs de ce groupe"></a>');$("#fenetre, #fenetre_fond").remove()}})})}function suppressionmultiple(){var prop=$(this).data("id").split("|");var contexte=$(this).parent().find("h3").text();var item="";switch(prop[2]){case"infos":item="toutes les informations de la page <em>"+contexte+"</em>";break;case"colles":item="tous les programmes de colles de la matière <em>"+contexte+"</em>";break;case"cdt":item="tout le contenu du cahier de texte de la matière <em>"+contexte+"</em>";break;case"docs":item="tous les répertoires et documents de la matière <em>"+contexte+"</em>";break;case"notes":item="toutes les notes de la matière <em>"+contexte+"</em>";break}confirmation("Vous allez supprimer XXX.<br>Cette opération n'est pas annulable.".replace("XXX",item),this,function(el){$.ajax({url:"ajax.php",method:"post",data:"action="+prop[0]+"&id="+prop[1]+"&supprime_"+prop[2]+"=1",dataType:"json",el:$(el),fonction:function(el){el.remove()}})})}function destinatairesmail(){popup($("#form-destinataires").html(),true);var f=$("#fenetre");$(".icon-deplie",f).on("click",plie);$("tr:not(.gr) input.dest",f).attr("id",function(){return"u"+this.value});$("tr:not(.categorie) td:nth-child(-n+2)",f).on("click",function(e){if(!$(e.target).is("input"))$(this).parent().find("input:first").click()});$("input",f).on("change",function(){var tr=$(this).parent().parent();if(this.checked)tr.find("input:not(."+this.className+")").prop("checked",false);tr.toggleClass("sel",tr.find("input:checked").length>0)});var ids=$('[name="id-copie"]').val();$("#u"+ids.replace(/,/g,",#u")).prop("checked",true).change();ids=$('[name="id-bcc"]').val();$("#u"+ids.replace(/,/g,",#u")).parent().next().children().prop("checked",true).change();$(".categorie a",f).on("click keyup",function(){var classe=this.className.split(" ")[1];var etat=this.className.split(" ")[0]=="icon-cocher";var titre=this.title;$(this).parent().parent().nextUntil(".categorie").find("."+classe+":not(:disabled)").prop("checked",etat).change();this.className=(etat?"icon-decocher ":"icon-cocher ")+classe;this.title=this.title.replace(etat?"Cocher":"Décocher",etat?"Décocher":"Cocher");var classe2=classe=="dest"?"bcc":"dest";$(this).parent().parent().find(".icon-decocher."+classe2).each(function(){this.className="icon-cocher "+classe2;this.title="C"+this.title.substr(3)})});$(".gr input",f).on("click",function(){var ids=this.value;if(this.className=="dest")$("#u"+ids.replace(/,/g,",#u")).prop("checked",this.checked).change();else $("#u"+ids.replace(/,/g,",#u")).parent().next().children().prop("checked",this.checked).change()});$(".icon-ok",f).on("click",function(){$('[name="id-copie"]').val($("tr:not(.gr) .dest:checked",f).map(function(){return this.value}).get().join(","));$('[name="id-bcc"]').val($("tr:not(.gr) .bcc:checked",f).map(function(){return this.value}).get().join(","));$("#maildest").text($("tr:not(.gr) .dest:checked",f).parent().prev().map(function(){return this.textContent}).get().concat($("tr:not(.gr) .bcc:checked",f).parent().prev().prev().map(function(){return this.textContent+" (CC)"}).get()).join(", ")||"[Personne]");$("#fenetre, #fenetre_fond").remove()})}function envoimail(){if($(".maildest").children("span").text()=="[Personne]")affiche("Il faut au moins un destinataire pour envoyer le courriel.","nok");else if(!$('[name="sujet"]').val().length)affiche("Il faut un sujet non vide pour envoyer le courriel.","nok");else $.ajax({url:"ajax.php",method:"post",data:$("#mail").serialize(),dataType:"json",el:"",fonction:function(el){location.reload(true)}})}function relevenotes(){confirmation("<p>Vous allez réaliser une relève des notes de colles. Cela consiste à marquer comme relevées toutes les heures déclarées jusqu'à maintenant et non encore relevées. Vous pourrez alors télécharger le nouveau relevé au sein du tableau en bas de page.</p><p>Cette opération n'est pas annulable.</p><p>Une fois que vous aurez réalisé ce relevé, les professeurs et colleurs ne pourront pas modifier le nombre d'élèves et la durée correspondant aux colles relevées.</p>",this,function(el){$.ajax({url:"ajax.php",method:"post",data:"action=releve-notes",dataType:"json",el:"",fonction:function(el){location.reload(true)}})})}$(document).ajaxSend(function(ev,xhr,settings){$("#load").show(200);if($("body").attr("data-csrf-token")!=undefined){if(settings.data.append)settings.data.append("csrf-token",$("body").attr("data-csrf-token"));else settings.data="csrf-token="+$("body").attr("data-csrf-token")+"&"+settings.data}}).ajaxStop(function(){$("#load").hide(200)}).ajaxSuccess(function(ev,xhr,settings){var data=xhr.responseJSON;switch(data["etat"]){case"ok":$("body").data("nepassortir",false);affiche(data["message"],"ok");settings.fonction(settings.el);break;case"nok":affiche(data["message"],"nok");break;case"login":case"mdp":reconnect(settings,data["etat"]=="mdp");break;case"recupok":settings.afficheform(data)}});$(function(){$("a.formulaire, .modifevnmt").on("click",formulaire);$("a.icon-aide").on("click",function(){popup($("#aide-"+($(this).parent().data("id")||"page").split("|")[0]).html(),false)});$("a.icon-ok").on("click",valide);$("a.icon-cache,a.icon-montre,a.icon-monte,a.icon-descend,a.icon-supprime,a.icon-lock,a.icon-ajoutecolle").on("click",function(){window[this.className.substring(5)]($(this))});$("#log").hide().on("click",function(){$(this).hide(300)});$(".editable").editinplace();$("a.icon-deconnexion").on("click",function(e){$.ajax({url:"ajax.php",method:"post",data:{action:"deconnexion"},dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$(".icon-menu").on("click",function(e){e.stopPropagation();$("nav").toggleClass("visible");if($("nav").hasClass("visible")){$('<div id="menu_fond"></div>').appendTo("body");$("#menu_fond").on("click",function(){$("#menu_fond").remove();$("nav").removeClass("visible")})}else $("#menu_fond").remove()});$("a.icon-echange").on("click",function(){$.ajax({url:"recup.php",method:"post",data:{action:"compteglobal"},dataType:"json",afficheform:function(data){popup("<h3>Changer de Cahier</h3><div></div>",true);var f=$("#fenetre");var cahiers=data["cahiers"];for(var rep in cahiers)$("div",f).attr("id","cahiers").append('<a href="/'+rep+'/">'+cahiers[rep]+"</a>")}})});$(".titrecdt").editinplacecdt();$(".cdt-raccourcis").init_cdt_raccourcis();$(".icon-mailenvoi").on("click",envoimail);$("#maildest, #maildest + .icon-edite").on("click",destinatairesmail);$(".categorie th:first-child").prepend($('<span class="icon-deplie" title="Déplier/Replier cette catégorie"></span>').on("click",plie));$("article select[multiple]").each(selmult);$(".supprmultiple").on("click",suppressionmultiple);$("#u").each(init_utilisateurs);$("#umats").each(init_utilisateurs_matieres);$("#envoimails").each(init_envoimails);$(".usergrp").first().each(init_utilisateurs_groupes);$("#planning select").change(function(){$(this).parent().prev().children("input").prop("checked",this.value==0)});$("#planning input").change(function(){$(this).parent().next().children("select").val(0)});$("#relevenotes").on("click",relevenotes);$("body").data("nepassortir",false);$("textarea:visible").on("change",function(e){$("body").data("nepassortir",true);$(this).off(e)});window.addEventListener("beforeunload",function(e){if($("body").data("nepassortir")){e.preventDefault();e.returnValue=""}})});
\ No newline at end of file
diff -urN cahier-de-prepa8.1.1/js/fonctions.js cahier-de-prepa9.0.0/js/fonctions.js
--- cahier-de-prepa8.1.1/js/fonctions.js	2018-10-16 10:56:18.090083852 +0200
+++ cahier-de-prepa9.0.0/js/fonctions.js	2019-08-25 22:52:51.233926037 +0200
@@ -13,16 +13,45 @@
   extinction = window.setTimeout(function() { $('#log').fadeOut(800); },6000);
 }
 
+// Affichage par-dessus le contenu de la page
+// * contenu : chaine en HTML qui sera utilisée comme contenu de la fenêtre
+// * modal : si true, fenêtre modale (impossible de continuer à éditer la page)
+function popup(contenu,modal) {
+  // Suppression d'une éventuelle fenêtre de la fonction popup existante
+  $('#fenetre,#fenetre_fond').remove();
+  // Création
+  var el = $('<article id="fenetre"></article>').appendTo('body').html(contenu).focus();
+  if ( modal )
+    $('<div id="fenetre_fond"></div>').appendTo('body').click(function() {
+      $('#fenetre,#fenetre_fond').remove();
+    });
+  // Si fenêtre non modale, possibilité de l'épingler en haut de la page
+  else
+    $('<a class="icon-epingle" title="Épingler à la page"></a>').prependTo(el).on("click",function() {
+      $('#fenetre_fond').remove();
+      $(this).remove();
+      el.removeAttr('id').insertBefore($('article,#calendrier,#parentsdoc+*').first());
+    });
+  // Bouton de fermeture
+  $('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function() {
+    el.remove();
+    $('#fenetre_fond').remove();
+  });
+}
+
+
 ///////////////////
 // Requêtes AJAX //
 ///////////////////
 $(document).ajaxSend( function(ev,xhr,settings) {
               $('#load').show(200);
               // Sécurité anti XSS : Ajout du token CSRF
-              if ( settings.data.append )
-                settings.data.append('csrf-token',$('body').attr('data-csrf-token'));
-              else
-                settings.data = 'csrf-token='+$('body').attr('data-csrf-token')+'&'+settings.data;
+              if ( $('body').attr('data-csrf-token') != undefined )  {
+                if ( settings.data.append )
+                  settings.data.append('csrf-token',$('body').attr('data-csrf-token'));
+                else
+                  settings.data = 'csrf-token='+$('body').attr('data-csrf-token')+'&'+settings.data;
+              }
             })
            .ajaxStop( function() {
               $('#load').hide(200);
@@ -108,16 +137,35 @@
     $.ajax({url: 'ajax.php', method: "post", data: { action:'deconnexion' }, dataType: 'json', el: '', fonction: function(el) { location.reload(true); } });
   });
 
-  // Menu pour les petits écrans
-  $('.icon-menu').on("click", function() {
-    $('nav').toggleClass('visible');
-    $('#recent').removeClass();
-    $('#colonne').toggleClass('visible',$('nav').hasClass('visible'));
+  // Affichage des informations sur le flux RSS
+  $('#aide-rss').each( function() {
+    $('a.icon-recent').replaceWith('<a class="icon-rss" title="Flux RSS"></a>');
+    $('a.icon-rss').on("click", function() {
+/*      var el = $('<div id="fenetre"></div>').appendTo('body').html($('.aide-rss').html());
+      $('<div id="fenetre_fond"></div>').appendTo('body').click(function() {
+        $('#fenetre,#fenetre_fond').remove();
+      });
+      $('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function() {
+        el.remove();
+        $('#fenetre_fond').remove();
+      });*/
+      popup($('#aide-rss').html(),false);
+    });
   });
-  $('.icon-recent').on("click", function() {
-    $('#recent').toggleClass('visible');
-    $('nav').removeClass();
-    $('#colonne').toggleClass('visible',$('#recent').hasClass('visible'));
+
+  // Menu mobile
+  $('.icon-menu').on("click", function(e) {
+    e.stopPropagation();
+    $('nav').toggleClass('visible');
+    if ( $('nav').hasClass('visible') )  {
+      $('<div id="menu_fond"></div>').appendTo('body');
+      $('nav,#menu_fond').on("click", function() {
+        $('#menu_fond').remove();
+        $('nav').removeClass('visible');
+      });
+    }
+    else 
+      $('#menu_fond').remove();
   });
 
   // Pop-up pour les événements de l'agenda
diff -urN cahier-de-prepa8.1.1/js/fonctions.min.js cahier-de-prepa9.0.0/js/fonctions.min.js
--- cahier-de-prepa8.1.1/js/fonctions.min.js	2018-10-16 10:57:56.471232706 +0200
+++ cahier-de-prepa9.0.0/js/fonctions.min.js	2019-08-28 19:37:35.281530762 +0200
@@ -1 +1 @@
-function affiche(message,etat){$("#log").removeClass().addClass(etat).html(message).append('<span class="icon-ferme"></span>').fadeIn().off("click").on("click",function(){window.clearTimeout(extinction);$(this).fadeOut(800)});extinction=window.setTimeout(function(){$("#log").fadeOut(800)},6e3)}$(document).ajaxSend(function(ev,xhr,settings){$("#load").show(200);if(settings.data.append)settings.data.append("csrf-token",$("body").attr("data-csrf-token"));else settings.data="csrf-token="+$("body").attr("data-csrf-token")+"&"+settings.data}).ajaxStop(function(){$("#load").hide(200)}).ajaxSuccess(function(ev,xhr,settings){var data=xhr.responseJSON;switch(data["etat"]){case"ok":affiche(data["message"],"ok");settings.fonction(settings.el);break;case"nok":affiche(data["message"],"nok");break}});$(function(){$("a.icon-connexion").on("click",function(e){if(!$("#log").length)$('<div id="log"></div>').appendTo("body").hide().on("click",function(){$(this).hide()});$("#colonne,nav").removeClass("visible");var el=$('<div id="fenetre"></div>').appendTo("body").html('<a class="icon-ferme" title="Fermer"></a><a class="icon-ok" title="Valider"></a><h3>Connexion</h3><form>  <p>Veuillez entrer votre identifiant et votre mot de passe&nbsp;:</p>  <input class="ligne" type="text" name="login" placeholder="Identifiant">  <input class="ligne" type="password" name="motdepasse" placeholder="Mot de passe">  <p class="oubli"><label for="permconn">Se souvenir de moi</label><input type="checkbox" name="permconn" id="permconn" value="1">  <p class="oubli"><a href="gestioncompte?oublimdp">Identifiant ou mot de passe oublié&nbsp;?</a></p>  <p class="oubli"><a href="gestioncompte?creation">Créer un compte</a></p></form>');$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme").on("click",function(){$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ok").on("click",function(){$.ajax({url:"ajax.php",method:"post",data:$("#fenetre form").serialize()+"&connexion=1",dataType:"json",el:"",beforeSend:function(){$("#load").show(200)},complete:function(){$("#load").hide(200)},fonction:function(el){location.reload(true)}}).done(function(data){if(data["etat"]=="nok")$("#fenetre form p:first").html(data["message"]).addClass("warning")})});$("#fenetre input").on("keypress",function(e){if(e.which==13){$("#fenetre a.icon-ok").click();return false}});$("#fenetre form input:first").focus()});$("a.icon-deconnexion").on("click",function(e){$.ajax({url:"ajax.php",method:"post",data:{action:"deconnexion"},dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$(".icon-menu").on("click",function(){$("nav").toggleClass("visible");$("#recent").removeClass();$("#colonne").toggleClass("visible",$("nav").hasClass("visible"))});$(".icon-recent").on("click",function(){$("#recent").toggleClass("visible");$("nav").removeClass();$("#colonne").toggleClass("visible",$("#recent").hasClass("visible"))});$(".evnmt").on("click",function(){var donnees=evenements[this.id.substr(1)];var el=$('<div id="fenetre"></div>').appendTo("body").html("<h3>"+donnees.titrebis+'</h3>\n<h3 style="margin-bottom: 1em;">'+donnees.date+"</h3>\n<p>"+donnees.texte+"</p>").focus();$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});$('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function(){el.remove();$("#fenetre_fond").remove()})})});
+function affiche(message,etat){$("#log").removeClass().addClass(etat).html(message).append('<span class="icon-ferme"></span>').fadeIn().off("click").on("click",function(){window.clearTimeout(extinction);$(this).fadeOut(800)});extinction=window.setTimeout(function(){$("#log").fadeOut(800)},6e3)}function popup(contenu,modal){$("#fenetre,#fenetre_fond").remove();var el=$('<article id="fenetre"></article>').appendTo("body").html(contenu).focus();if(modal)$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});else $('<a class="icon-epingle" title="Épingler à la page"></a>').prependTo(el).on("click",function(){$("#fenetre_fond").remove();$(this).remove();el.removeAttr("id").insertBefore($("article,#calendrier,#parentsdoc+*").first())});$('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function(){el.remove();$("#fenetre_fond").remove()})}$(document).ajaxSend(function(ev,xhr,settings){$("#load").show(200);if($("body").attr("data-csrf-token")!=undefined){if(settings.data.append)settings.data.append("csrf-token",$("body").attr("data-csrf-token"));else settings.data="csrf-token="+$("body").attr("data-csrf-token")+"&"+settings.data}}).ajaxStop(function(){$("#load").hide(200)}).ajaxSuccess(function(ev,xhr,settings){var data=xhr.responseJSON;switch(data["etat"]){case"ok":affiche(data["message"],"ok");settings.fonction(settings.el);break;case"nok":affiche(data["message"],"nok");break}});$(function(){$("a.icon-connexion").on("click",function(e){if(!$("#log").length)$('<div id="log"></div>').appendTo("body").hide().on("click",function(){$(this).hide()});$("#colonne,nav").removeClass("visible");var el=$('<div id="fenetre"></div>').appendTo("body").html('<a class="icon-ferme" title="Fermer"></a><a class="icon-ok" title="Valider"></a><h3>Connexion</h3><form>  <p>Veuillez entrer votre identifiant et votre mot de passe&nbsp;:</p>  <input class="ligne" type="text" name="login" placeholder="Identifiant">  <input class="ligne" type="password" name="motdepasse" placeholder="Mot de passe">  <p class="oubli"><label for="permconn">Se souvenir de moi</label><input type="checkbox" name="permconn" id="permconn" value="1">  <p class="oubli"><a href="gestioncompte?oublimdp">Identifiant ou mot de passe oublié&nbsp;?</a></p>  <p class="oubli"><a href="gestioncompte?creation">Créer un compte</a></p></form>');$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ferme").on("click",function(){$("#fenetre,#fenetre_fond").remove()});$("#fenetre a.icon-ok").on("click",function(){$.ajax({url:"ajax.php",method:"post",data:$("#fenetre form").serialize()+"&connexion=1",dataType:"json",el:"",beforeSend:function(){$("#load").show(200)},complete:function(){$("#load").hide(200)},fonction:function(el){location.reload(true)}}).done(function(data){if(data["etat"]=="nok")$("#fenetre form p:first").html(data["message"]).addClass("warning")})});$("#fenetre input").on("keypress",function(e){if(e.which==13){$("#fenetre a.icon-ok").click();return false}});$("#fenetre form input:first").focus()});$("a.icon-deconnexion").on("click",function(e){$.ajax({url:"ajax.php",method:"post",data:{action:"deconnexion"},dataType:"json",el:"",fonction:function(el){location.reload(true)}})});$("#aide-rss").each(function(){$("a.icon-recent").replaceWith('<a class="icon-rss" title="Flux RSS"></a>');$("a.icon-rss").on("click",function(){popup($("#aide-rss").html(),false)})});$(".icon-menu").on("click",function(e){e.stopPropagation();$("nav").toggleClass("visible");if($("nav").hasClass("visible")){$('<div id="menu_fond"></div>').appendTo("body");$("nav,#menu_fond").on("click",function(){$("#menu_fond").remove();$("nav").removeClass("visible")})}else $("#menu_fond").remove()});$(".evnmt").on("click",function(){var donnees=evenements[this.id.substr(1)];var el=$('<div id="fenetre"></div>').appendTo("body").html("<h3>"+donnees.titrebis+'</h3>\n<h3 style="margin-bottom: 1em;">'+donnees.date+"</h3>\n<p>"+donnees.texte+"</p>").focus();$('<div id="fenetre_fond"></div>').appendTo("body").click(function(){$("#fenetre,#fenetre_fond").remove()});$('<a class="icon-ferme" title="Fermer"></a>').prependTo(el).on("click",function(){el.remove();$("#fenetre_fond").remove()})})});
\ No newline at end of file
diff -urN cahier-de-prepa8.1.1/mail.php cahier-de-prepa9.0.0/mail.php
--- cahier-de-prepa8.1.1/mail.php	2018-10-13 01:21:06.436259701 +0200
+++ cahier-de-prepa9.0.0/mail.php	2019-08-28 02:58:42.679153996 +0200
@@ -18,19 +18,17 @@
   $actuel = false;
   include('login.php');
 }
-/*/ Récupération de la valeur si non déjà stockée dans la session - a priori inutile
-elseif ( !isset($_SESSION['mailenvoi']) )  {
-  $resultat = $mysqli->query("SELECT mailenvoi FROM utilisateurs WHERE id = ${_SESSION['id']}");
-  $r = $resultat->fetch_row();
-  $resultat->free();
-  $_SESSION['mailenvoi'] = $r[0];
-}*/
-if ( $_SESSION['mailenvoi'] == 0 )  {
+// Récupération de l'autorisation d'envoi de courriels
+$resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+$aut_envoi = $resultat->fetch_row()[0] >> 4*($autorisation-2) & 15;
+$resultat->free();
+if ( !$aut_envoi )  {
   debut($mysqli,'Envoi de courriel','Vous n\'avez pas accès à cette page.',$autorisation,' ');
   $mysqli->close();
   fin();
 }
-
+$aut_dest = array_reverse(array_keys(str_split('00'.strrev(decbin($aut_envoi))),1));
+    
 //////////////
 //// HTML ////
 //////////////
@@ -41,7 +39,7 @@
                             FROM utilisateurs WHERE id = ${_SESSION['id']}");
 $u = $resultat->fetch_assoc();
 $resultat->free();
-echo <<<FIN
+?>
 
   <div id="icones">
     <a class="icon-aide" data-id="page" title="Aide pour l'envoi de courriel"></a>
@@ -49,16 +47,16 @@
 
   <article>
     <a class="icon-mailenvoi" title="Envoyer le courriel"></a>
-    <p><strong>Nom de l'expéditeur&nbsp;: </strong>&nbsp;${u['mailexp']}</p>
-    <p><strong>Adresse électronique&nbsp;: </strong>&nbsp;${u['mail']}</p>
+    <p><strong>Nom de l'expéditeur&nbsp;: </strong>&nbsp;<?php echo $u['mailexp']; ?></p>
+    <p><strong>Adresse électronique&nbsp;: </strong>&nbsp;<?php echo $u['mail']; ?></p>
     <p><strong>Destinataires&nbsp;: </strong>&nbsp;<span id="maildest">[Personne]</span>&nbsp;<a class="icon-edite"></a></p>
     <p><strong>Sujet&nbsp;:</strong></p>
     <form id="mail">
       <input class="ligne" type="text" name="sujet">
       <p><strong>Texte du message&nbsp;:</strong></p>
-      <textarea name="texte" rows="20" cols="100">\n\n\n\n-- \n${u['mailexp']}\nMail envoyé depuis <https://$site/></textarea>
+      <textarea name="texte" rows="20" cols="100"><?php echo "\n\n\n\n-- \n${u['mailexp']}\nMail envoyé depuis <https://$domaine$chemin"; ?>></textarea>
       <p class="ligne"><label for="copie">Recevoir le courriel en copie&nbsp;: </label>
-        <input type="checkbox" id="copie" name="copie" value="1"${u['mailcopie']}>
+        <input type="checkbox" id="copie" name="copie" value="1"<?php echo $u['mailcopie']; ?>>
       </p>
       <input type="hidden" name="id-copie" value="">
       <input type="hidden" name="id-bcc" value="">
@@ -69,58 +67,53 @@
 
   <p id="log"></p>
 
-FIN;
+  <div id="form-destinataires">
+    <a class="icon-ok" title="Valider ces destinataires"></a>
+    <h3>Choix des destinataires</h3>
+    <form>
+    <table class="utilisateurs">
+      <thead>
+        <tr><th></th><th class="icone">Copie</th><th class="icone">Copie cachée</th></tr>
+      </thead>
+      <tbody>
 
-// Récupération de tous les utilisateurs
-// Requête différente pour un élève ou pour un autre type de compte
-if ( $autorisation == 2 )
-  $resultat = $mysqli->query("SELECT id, autorisation, '' AS pasmail,
-                              IF(autorisation=2,
-                                CONCAT(nom,' ',prenom),
-                                IF(LENGTH(mailexp),mailexp,CONCAT(nom,' ',prenom))) AS nomcomplet
-                              FROM utilisateurs WHERE mdp > '0' AND mailliste = 1 AND id != ${_SESSION['id']}
-                              ORDER BY autorisation DESC, nom, prenom, login");
-else
-  $resultat = $mysqli->query("SELECT id, autorisation, IF(LENGTH(mail),'',' disabled') AS pasmail,
-                              IF(LENGTH(nom),CONCAT(nom,' ',prenom),CONCAT('<em>',login,'</em>')) AS nomcomplet
-                              FROM utilisateurs WHERE mdp > '0' AND autorisation > 1 AND id != ${_SESSION['id']}
-                              ORDER BY autorisation DESC, nom, prenom, login");
-$a = 0;
-$table = '';
-while ( $r = $resultat->fetch_assoc() )  {
-  if ( $a != $r['autorisation'] )  {
-    $a = $r['autorisation'];
+<?php
+
+// Récupération de tous les utilisateurs pouvant être destinataires, en fonction du réglage global
+foreach ( $aut_dest as $a )  {
+  $resultat = $mysqli->query("SELECT id, mailexp FROM utilisateurs WHERE autorisation = $a AND mdp > '0' AND LENGTH(mail) AND id != ${_SESSION['id']} ORDER BY nom, prenom, login");
+  if ( $resultat->num_rows )  {
     switch ( $a )  {
       case 2 : $t = 'Élèves'; break;
       case 3 : $t = 'Colleurs'; break;
-      case 4 : $t = 'Administratifs'; break;
+      case 4 : $t = 'Lycée'; break;
       case 5 : $t = 'Professeurs'; break;
     }
-    $table .= <<<FIN
+    echo <<<FIN
         <tr class="categorie">
           <th>$t</th>
-          <th><a class="icon-cocher dest" title="Cocher tous les $t en copie"></a></th>
-          <th><a class="icon-cocher bcc" title="Cocher tous les $t en copie cachée"></a></th>
+          <th class="icone"><a class="icon-cocher dest" title="Cocher tous les $t en copie"></a></th>
+          <th class="icone"><a class="icon-cocher bcc" title="Cocher tous les $t en copie cachée"></a></th>
         </tr>
 
 FIN;
   }
-  if ( strlen($r['pasmail']) )
-    $r['nomcomplet'] .= ' (pas d\'adresse)';
-  $table .= "        <tr><td>${r['nomcomplet']}</td><td><input type=\"checkbox\" class=\"dest\" value=\"${r['id']}\"${r['pasmail']}></td><td><input type=\"checkbox\" class=\"bcc\" value=\"${r['id']}\"${r['pasmail']}></td></tr>\n";
+  while ( $r = $resultat->fetch_assoc() )
+    echo "        <tr><td>${r['mailexp']}</td><td class=\"icone\"><input type=\"checkbox\" class=\"dest\" value=\"${r['id']}\"></td><td class=\"icone\"><input type=\"checkbox\" class=\"bcc\" value=\"${r['id']}\"></td></tr>\n";
+  $resultat->free();
 }
-$resultat->free();
 
 // Récupération des groupes d'utilisateurs, pour les comptes non élèves seulement
 if ( $autorisation > 2 )  {
   $resultat = $mysqli->query('SELECT g.id, g.nom, g.utilisateurs AS uid,
-                              GROUP_CONCAT( IF(LENGTH(u.nom),CONCAT(u.prenom," ",u.nom),u.login) ORDER BY u.nom SEPARATOR \', \') AS noms
+                              GROUP_CONCAT( u.mailexp ORDER BY u.nom SEPARATOR \', \') AS noms
                               FROM groupes AS g JOIN utilisateurs AS u ON FIND_IN_SET(u.id,g.utilisateurs)
-                              WHERE g.mails AND u.mdp > \'0\' GROUP BY g.id ORDER BY g.nom_nat');
+                              WHERE g.mails AND u.mdp > \'0\' AND LENGTH(u.mail) AND FIND_IN_SET(u.autorisation,\''.implode(',',array_keys($aut_dest,1)).'\')
+                              GROUP BY g.id ORDER BY g.nom_nat');
   if ( $resultat->num_rows )  {
-    $table .= "        <tr class=\"categorie\"><th>Groupes d'élèves</th><th></th><th></th></tr>\n";
+    echo "        <tr class=\"categorie\"><th>Groupes d'élèves</th><th></th><th></th></tr>\n";
     while ( $r = $resultat->fetch_assoc() )
-      $table .= "        <tr class=\"gr\"><td>Groupe ${r['nom']}&nbsp;: ${r['noms']}</td><td><input type=\"checkbox\" class=\"dest\" value=\"${r['uid']}\"></td><td><input type=\"checkbox\" class=\"bcc\" value=\"${r['uid']}\"></td></tr>\n";
+      echo "        <tr class=\"gr\"><td>Groupe ${r['nom']}&nbsp;: ${r['noms']}</td><td class=\"icone\"><input type=\"checkbox\" class=\"dest\" value=\"${r['uid']}\"></td><td class=\"icone\"><input type=\"checkbox\" class=\"bcc\" value=\"${r['uid']}\"></td></tr>\n";
     $resultat->free();
   }
 }
@@ -129,16 +122,6 @@
 // Aide et formulaire d'ajout
 ?>
 
-  <div id="form-destinataires">
-    <a class="icon-ok" title="Valider ces destinataires"></a>
-    <h3>Choix des destinataires</h3>
-    <form>
-    <table>
-      <thead>
-        <tr><th></th><th>Copie</th><th>Copie cachée</th></tr>
-      </thead>
-      <tbody>
-<?php echo $table; ?>
       </tbody>
     </table>
     </form>
@@ -151,12 +134,12 @@
 
   <div id="aide-page">
     <h3>Aide et explications</h3>
-    <p>Il est possible ici d'envoyer un courriel aux camarades de la classe, aux colleurs ou aux professeurs. L'envoi du courriel est réalisé lors du clic sur le bouton <span class="icon-mailenvoi" style="font-size: 1em;"></span>.</p>
+    <p>Il est possible ici d'envoyer un courriel à certains utilisateurs, selon un choix défini par les professeurs. L'envoi du courriel est réalisé lors du clic sur le bouton <span class="icon-mailenvoi" style="font-size: 1em;"></span>.</p>
     <h4>Expéditeur</h4>
     <p>Le <em>nom d'expéditeur</em>, l'<em>adresse électronique</em> et le réglage par défaut de la <em>mise en copie des courriels</em> sont modifiables sur la page de <a href="prefs">vos préférences personnelles</a>.</p>
     <p>Le courriel sera envoyé en votre nom mais avec une adresse électronique différente de la vôtre pour éviter d'être considéré comme du spam. Le retour du mail sera positionné sur votre adresse électronique&nbsp;: si vos correspondants répondent à ce mail, ils devraient automatiquement vous répondre.</p>
     <h4>Destinataires</h4>
-    <p>La liste des destinataires est éditable à tout moment en cliquant sur le bouton <span class="icon-edite"></span>. Cela ouvre une fenêtre dans laquelle on peut cocher les destinataires. Le bouton <span class="icon-ok"></span> de cette fenêtre valide la liste des destinataires uniquement, n'envoie pas le courriel. Seuls les colleurs et professeurs ayant accepté d'être contactés se trouvent dans cette liste.</p>
+    <p>La liste des destinataires est éditable à tout moment en cliquant sur le bouton <span class="icon-edite"></span>. Cela ouvre une fenêtre dans laquelle on peut cocher les destinataires. Le bouton <span class="icon-ok"></span> de cette fenêtre valide la liste des destinataires uniquement, n'envoie pas le courriel.</p>
     <p>Les cases à cocher <em>Copie</em> permettent d'ajouter les utilisateurs cochés dans la liste des destinataires visibles. Il est obligatoire qu'au moins un utilisateur soit destinataire.</p>
     <p>Les cases à cocher <em>Copie cachée</em> permettent d'ajouter les utilisateurs cochés dans la liste des destinataires en copie cachée&nbsp;: les autres destinataires ne verront pas que ce courriel a aussi été envoyé à ceux en copie cachée.</p>
     <p>Un utilisateur ne peut pas être à la fois en copie et en copie cachée.</p>
@@ -182,8 +165,7 @@
 
   <div id="aide-page">
     <h3>Aide et explications</h3>
-    <p>Il est possible ici d'envoyer un courriel aux utilisateurs ayant renseigné leur adresse électronique, qu'il s'agisse d'élèves, de colleurs ou de professeurs. L'envoi du courriel est réalisé lors du clic sur le bouton <span class="icon-mailenvoi" style="font-size: 1em;"></span>.</p>
-    <p>Les élèves peuvent être autorisés à envoyer aussi des courriels par cette interface. Dans ce cas, ils verront une liste contenant tous les élèves et uniquement les utilisateurs colleurs/administration/professeurs ayant validé leur présence sur cette liste dans leurs préférences.</p>
+    <p>Il est possible ici d'envoyer un courriel aux utilisateurs ayant renseigné leur adresse électronique, selon les réglages modifiables sur la page de <a href="utilisateurs-mails">gestion des courriels</a>. L'envoi du courriel est réalisé lors du clic sur le bouton <span class="icon-mailenvoi" style="font-size: 1em;"></span>.</p>
     <h4>Expéditeur</h4>
     <p>Le <em>nom d'expéditeur</em>, l'<em>adresse électronique</em> et le réglage par défaut de la <em>mise en copie des courriels</em> sont modifiables sur la page de <a href="prefs">vos préférences personnelles</a>.</p>
     <p>Le courriel sera envoyé en votre nom mais avec une adresse électronique différente de la vôtre pour éviter d'être considéré comme du spam. Le retour du mail sera positionné sur votre adresse électronique&nbsp;: si vos correspondants répondent à ce mail, ils devraient automatiquement vous répondre.</p>
@@ -192,11 +174,10 @@
     <p>Un utilisateur ne peut pas être à la fois en copie et en copie cachée.</p>
     <p>Les cases à cocher <em>Copie</em> permettent d'ajouter les utilisateurs cochés dans la liste des destinataires. Il est obligatoire qu'au moins un utilisateur soit destinataire.</p>
     <p>Les cases à cocher <em>Copie cachée</em> permettent d'ajouter les utilisateurs cochés dans la liste des destinataires en copie cachée&nbsp;: les autres destinataires ne verront pas que ce courriel a aussi été envoyé à ceux en copie cachée.</p>
-    <p>Les cases à cocher sont grisées si l'utilisateur n'a pas renseigné son adresse électronique.</p>
     <p>Un clic sur le nom d'un utilisateur est équivalent à un clic sur la case <em>Copie</em> associée.</p>
     <p>Les boutons <span class="icon-cocher"></span> permettent de cocher l'ensemble des utilisateurs du type correspondant.</p>
     <h4>Groupes d'utilisateurs</h4>
-    <p>Si des groupes d'utilisateurs ont été établis, ils apparaissent en bas de la liste des destinataires. Cliquer sur les cases correspondantes ou le nom d'un groupe permet de sélectionner automatiquement les utilisateurs concernés.</p><?php if ( $autorisation == 5 ) echo '<p>Les groupes d\'utilisateurs peuvent être définis ou modifiés à la <a href="groupes">gestion des groupes</a>.</p>'; ?>
+    <p>Si des groupes d'utilisateurs ont été établis, ils apparaissent en bas de la liste des destinataires. Cliquer sur les cases correspondantes ou le nom d'un groupe permet de sélectionner automatiquement les utilisateurs concernés.</p><?php if ( $autorisation == 5 ) echo '<p>Les groupes d\'utilisateurs peuvent être définis ou modifiés sur la page de <a href="groupes">gestion des groupes</a>.</p>'; ?>
     <h4>Sujet et contenu du courriel</h4>
     <p>Le <em>sujet</em> est le titre du courriel. Tous les caractères sont autorisés. Pensez à envoyer des courriels avec un sujet correspondant explicitement au contenu...</p>
     <p>Le <em>contenu</em> est le corps du courriel, en texte brut. Le courriel envoyé ne sera pas formaté en HTML&nbsp;: il n'est pas possible de réaliser un formattage particulier (changer une taille d'écriture, une police, mettre de la couleur...). Par convention classique,</p>
diff -urN cahier-de-prepa8.1.1/MAJSQL.sql cahier-de-prepa9.0.0/MAJSQL.sql
--- cahier-de-prepa8.1.1/MAJSQL.sql	2018-10-27 23:58:40.422670805 +0200
+++ cahier-de-prepa9.0.0/MAJSQL.sql	2019-08-29 07:03:04.735246181 +0200
@@ -496,3 +496,87 @@
 --
 ALTER TABLE heurescolles 
   ADD description VARCHAR(200) NOT NULL AFTER duree;
+
+--
+-- Voilà les modifications à effectuer sur chaque base pour passer de Cahier de
+-- Prépa 8.1.0 à Cahier de Prépa 9.0.0
+--
+
+-- Nouvelle table : affichage configurable des vacances
+CREATE TABLE vacances (
+  id tinyint(2) unsigned NOT NULL PRIMARY KEY,
+  nom varchar(50) NOT NULL
+) ENGINE=MyISAM DEFAULT CHARSET=utf8;
+-- Modifications des tables existantes
+DELETE FROM prefs WHERE nom = 'protection_globale' OR nom = 'envoi_mail_defaut';
+ALTER TABLE prefs CHANGE val val SMALLINT( 3 ) UNSIGNED NOT NULL;
+INSERT INTO prefs (nom,val) VALUES ('autorisation_mails',61440);
+ALTER TABLE utilisateurs DROP mailenvoi, DROP mailliste;
+UPDATE utilisateurs SET mailexp = CONCAT(prenom,' ',nom) WHERE LENGTH(mailexp) = 0;
+-- Nouvelle structure des contenus récents
+ALTER TABLE recents 
+  DROP PRIMARY KEY,
+  DROP KEY heure,
+  ADD type TINYINT( 1 ) UNSIGNED NOT NULL AFTER id,
+  CHANGE heure publi DATETIME NOT NULL,
+  ADD maj DATETIME NOT NULL AFTER publi,
+  ADD PRIMARY KEY (id, type),
+  ADD KEY publi (publi),
+  ADD KEY maj (maj);
+UPDATE recents SET type = 1, id = id-1000,
+                   titre = ( SELECT CONCAT( IF(LENGTH(i.titre),i.titre,'Information'),' [',IF(mat=0,'',CONCAT(m.nom,'/')),p.nom,']')
+                             FROM infos AS i LEFT JOIN pages AS p ON page=p.id LEFT JOIN matieres AS m ON mat=m.id WHERE i.id = recents.id )
+WHERE id < 2000;
+DELETE FROM recents WHERE id > 2000;
+INSERT INTO recents (id,type,publi,matiere,titre,lien,texte,protection)
+  SELECT d.id, 3, upload, d.matiere, d.nom AS titre, CONCAT('download?id=',d.id) AS lien, 
+  CONCAT(ext,'|',taille,'|',d.parent,'|',GROUP_CONCAT( r.nom ORDER BY FIND_IN_SET(r.id,d.parents) SEPARATOR '/' )) AS texte, d.protection
+  FROM docs AS d LEFT JOIN reps AS r ON FIND_IN_SET(r.id,d.parents) GROUP BY d.id;
+ALTER TABLE recents ORDER BY publi DESC;
+-- Semaines 2019-2020
+TRUNCATE TABLE semaines;
+TRUNCATE TABLE cdt;
+TRUNCATE TABLE colles;
+TRUNCATE TABLE notes;
+DELETE FROM agenda WHERE fin < '2019-09-01';
+UPDATE matieres SET colles = 0, cdt = 0, notes = 0;
+INSERT INTO semaines (id,debut) VALUES 
+   (1,'2019-09-02'), (2,'2019-09-09'), (3,'2019-09-16'), (4,'2019-09-23'), (5,'2019-09-30'),
+   (6,'2019-10-07'), (7,'2019-10-14'), (8,'2019-10-21'), (9,'2019-10-28'),(10,'2019-11-04'),
+  (11,'2019-11-11'),(12,'2019-11-18'),(13,'2019-11-25'),(14,'2019-12-02'),(15,'2019-12-09'),
+  (16,'2019-12-16'),(17,'2019-12-23'),(18,'2019-12-30'),(19,'2020-01-06'),(20,'2020-01-13'),
+  (21,'2020-01-20'),(22,'2020-01-27'),(23,'2020-02-03'),(24,'2020-02-10'),(25,'2020-02-17'),
+  (26,'2020-02-24'),(27,'2020-03-02'),(28,'2020-03-09'),(29,'2020-03-16'),(30,'2020-03-23'),
+  (31,'2020-03-30'),(32,'2020-04-06'),(33,'2020-04-13'),(34,'2020-04-20'),(35,'2020-04-27'),
+  (36,'2020-05-04'),(37,'2020-05-11'),(38,'2020-05-18'),(39,'2020-05-25'),(40,'2020-06-01'),
+  (41,'2020-06-08'),(42,'2020-06-15'),(43,'2020-06-22'),(44,'2020-06-29');
+UPDATE semaines SET vacances = 1 WHERE id = 8 OR id = 9;
+UPDATE semaines SET vacances = 2 WHERE id = 17 OR id = 18;
+UPDATE semaines SET vacances = 3 WHERE id = 24 OR id = 25;
+UPDATE semaines SET vacances = 4 WHERE id = 32 OR id = 33;
+UPDATE semaines SET colle = 1 WHERE vacances = 0;
+INSERT INTO vacances (id, nom) VALUES
+  (0, ''),
+  (1, 'Vacances de la Toussaint'),
+  (2, 'Vacances de Noël'),
+  (3, "Vacances d'hiver"),
+  (4, 'Vacances de printemps');
+
+INSERT INTO agenda (id,matiere,debut,fin,type,texte) VALUES 
+  ( 1, 0, '2019-09-02 00:00:00', '2019-09-02 00:00:00', 3, '<div class="annonce">C''est la rentrée ! Bon courage pour cette nouvelle année&nbsp;!</div>'),
+  ( 2, 0, '2019-11-01 00:00:00', '2019-11-01 00:00:00', 7, '<p>Toussaint</p>'),
+  ( 3, 0, '2019-11-11 00:00:00', '2019-11-11 00:00:00', 7, '<p>Armistice 1918</p>'),
+  ( 4, 0, '2019-12-25 00:00:00', '2019-12-25 00:00:00', 7, '<p>Noël</p>'),
+  ( 5, 0, '2020-01-01 00:00:00', '2020-01-01 00:00:00', 7, '<p>Jour de l''an</p>'),
+  ( 6, 0, '2020-04-13 00:00:00', '2020-04-13 00:00:00', 7, '<p>Lundi de Pâques</p>'),
+  ( 7, 0, '2020-05-01 00:00:00', '2020-05-01 00:00:00', 7, '<p>Fête du travail</p>'),
+  ( 8, 0, '2020-05-08 00:00:00', '2020-05-08 00:00:00', 7, '<p>Armistice 1945</p>'),
+  ( 9, 0, '2020-05-21 00:00:00', '2020-05-24 00:00:00', 7, '<p>Pont de l''Ascension</p>'),
+  (10, 0, '2020-06-01 00:00:00', '2020-06-01 00:00:00', 7, '<p>Lundi de Pentecôte</p>'),
+  (11, 0, '2020-07-14 00:00:00', '2020-07-14 00:00:00', 7, '<p>Fête Nationale</p>'),
+  (12, 0, '2019-07-07 00:00:00', '2019-09-01 00:00:00', 8, '<p>Vacances d''été</p>'),
+  (13, 0, '2019-10-20 00:00:00', '2019-11-03 00:00:00', 8, '<p>Vacances de la Toussaint</p>'),
+  (14, 0, '2019-12-22 00:00:00', '2020-01-05 00:00:00', 8, '<p>Vacances de Noël</p>'),
+  (15, 0, '2020-02-09 00:00:00', '2020-02-23 00:00:00', 8, '<p>Vacances d''hiver</p>'),
+  (16, 0, '2020-04-05 00:00:00', '2020-04-19 00:00:00', 8, '<p>Vacances de printemps</p>'),
+  (17, 0, '2020-07-05 00:00:00', '2020-09-01 00:00:00', 8, '<p>Vacances d''été</p>');
diff -urN cahier-de-prepa8.1.1/matieres.php cahier-de-prepa9.0.0/matieres.php
--- cahier-de-prepa8.1.1/matieres.php	2018-10-14 03:00:44.288099342 +0200
+++ cahier-de-prepa9.0.0/matieres.php	2019-08-20 02:40:04.246345045 +0200
@@ -12,7 +12,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
@@ -42,7 +42,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Adminstratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Fonction désactivée</option>';
 
diff -urN cahier-de-prepa8.1.1/notes.php cahier-de-prepa9.0.0/notes.php
--- cahier-de-prepa8.1.1/notes.php	2018-11-06 01:19:05.638505108 +0100
+++ cahier-de-prepa9.0.0/notes.php	2019-08-28 01:51:39.739013552 +0200
@@ -167,6 +167,35 @@
       while ( $r = $resultat->fetch_assoc() )
         $select_colleurs .= "\n      <option value=\"${r['id']}\">${r['nom']}</option>";
       $resultat->free();
+      // Récupération des semaines
+      $resultat = $mysqli->query("SELECT id, IF(LENGTH(nom),CONCAT(prenom,' ',nom),login) AS nom
+                                  FROM utilisateurs WHERE ( autorisation = 3 OR autorisation = 5 ) AND FIND_IN_SET($mid,matieres) ORDER BY IF(LENGTH(nom),nom,login)");
+      $select_colleurs = '';
+      while ( $r = $resultat->fetch_assoc() )
+        $select_colleurs .= "\n      <option value=\"${r['id']}\">${r['nom']}</option>";
+      $resultat->free();
+      
+      $resultat = $mysqli->query('SELECT id, DATE_FORMAT(debut,\'%w%Y%m%e\') AS debut, DATE_FORMAT(ADDDATE(debut,7-DAYOFWEEK(debut)),\'%w%Y%m%e\') AS fin FROM semaines WHERE colle = 1');
+      if ( $resultat->num_rows )  {
+        $semaines_debut = $semaines_fin = '';
+        while ( $r = $resultat->fetch_assoc() )  {
+          $semaines_debut .= "\n      <option value=\"${r['id']}\">".format_date($r['debut']).'</option>';
+          $semaines_fin .= "\n      <option value=\"${r['id']}\">".format_date($r['fin']).'</option>';
+          $nmax = $r['id'];
+        }
+        $resultat->free();
+        if ( !isset($_REQUEST['ndebut']) || !ctype_digit($ndebut = $_REQUEST['ndebut']) || ( $ndebut < 1 ) || ( $ndebut > $nmax ) )
+          $ndebut = 1;
+        if ( !isset($_REQUEST['nfin']) || !ctype_digit($nfin = $_REQUEST['nfin']) || ( $nfin < $ndebut ) || ( $nfin > $nmax ) )
+          $nfin = $nmax;
+        $select_semaines = "\n    entre <select id=\"sdebut\" onchange=\"window.location.href='?${matiere['cle']}&amp;tableau&amp;ndebut='+this.value+'&amp;nfin='+document.getElementById('sfin').value\">".str_replace("\"$ndebut\"","\"$ndebut\" selected",$semaines_debut)."\n    </select> et <select id=\"sfin\" onchange=\"window.location.href='?${matiere['cle']}&amp;tableau&amp;ndebut='+document.getElementById('sdebut').value+'&amp;nfin='+this.value\">".str_replace("\"$nfin\"","\"$nfin\" selected",$semaines_fin)."\n    </select>";
+      }
+      // S'il n'y a pas de semaines de colles dans le planning, la suite n'a pas de sens
+      else  {
+        $select_semaines = '';
+        $ndebut = $nfin = 0;
+      }
+      
       // Icônes d'action générales et barre de sélection
       echo <<<FIN
 
@@ -178,7 +207,7 @@
   <p id="recherchenote" class="topbarre">
     Voir les notes de <select id="colleurs" onchange="if (this.value>0) { $('[data-colleur]').attr('class','collnosel'); $('[data-colleur=&quot;'+this.value+'&quot;]').attr('class','collsel'); } else $('[data-colleur]').removeClass();">
       <option value="0">tous les colleurs</option>$select_colleurs
-    </select>
+    </select>$select_semaines
   </p>
 
 FIN;
@@ -186,15 +215,16 @@
       $resultat = $mysqli->query("SELECT nom, GROUP_CONCAT( IF(ISNULL(note),'<td></td>',CONCAT('<td data-colleur=\"',colleur,'\">',note,'</td>')) ORDER BY sid SEPARATOR '') AS notes,
                                   LEFT(REPLACE(AVG(IF(note='abs' OR note='nn',NULL,REPLACE(note,',','.'))),'.',','),4) AS moyenne
                                   FROM ( SELECT s.id AS sid,  u.id AS eid, CONCAT('<td>',IF(LENGTH(nom),CONCAT(nom,' ',prenom),login),'</td>') AS nom
-                                         FROM semaines AS s LEFT JOIN utilisateurs AS u ON 1 WHERE colle AND u.autorisation=2 AND FIND_IN_SET($mid,u.matieres) ORDER BY IF(LENGTH(nom),nom,login)) AS t
+                                         FROM semaines AS s LEFT JOIN utilisateurs AS u ON 1 
+                                         WHERE colle AND s.id >= $ndebut AND s.id <= $nfin AND u.autorisation=2 AND FIND_IN_SET($mid,u.matieres) ORDER BY IF(LENGTH(nom),nom,login)) AS t
                                   LEFT JOIN notes ON sid = semaine AND eid = eleve AND matiere = $mid GROUP BY eid ORDER BY nom,sid");
       if ( $resultat->num_rows )  {
         echo "\n  <table>\n    <thead>\n      <tr><th></th>";
-        $semaines = $mysqli->query('SELECT DATE_FORMAT(debut,\'%d/%m\') FROM semaines WHERE colle');
+        $semaines = $mysqli->query("SELECT DATE_FORMAT(debut,'%d/%m') FROM semaines WHERE colle AND id >= $ndebut AND id <= $nfin");
         $nb = $semaines->num_rows;
         while ( $r = $semaines->fetch_row() )
-          echo "<th class=\"semaines\"><span>${r[0]}</span></th>";
-        echo '<th class="semaines"><span>Moyenne</span></th>';
+          echo "<th class=\"vertical\"><span>${r[0]}</span></th>";
+        echo '<th class="vertical"><span>Moyenne</span></th>';
         $semaines->free();
         echo "</tr>\n    </thead>\n    <tbody>\n";
         while ( $r = $resultat->fetch_assoc() )
@@ -248,7 +278,7 @@
         $resultat2 = $mysqli->query("SELECT COUNT(*) AS nb, LEFT(REPLACE(AVG(IF(note='abs' OR note='nn',NULL,REPLACE(note,',','.'))),'.',','),4) AS moy FROM notes WHERE colleur = ${r['cid']} AND matiere = $mid");
         $s = $resultat2->fetch_assoc();
         $resultat2->free();
-        echo "          <th class=\"colleurs\"><span>${r['cnom']}</span></th>\n";
+        echo "          <th class=\"vertical\"><span>${r['cnom']}</span></th>\n";
         $ligne_eleves .= "<td>${s['nb']}</td>";
         $ligne_heures_rel .= '<td>'.format_duree($r['total_rel']).( $r['td_rel'] ? '&nbsp;('.format_duree($r['td_rel']).')' : '' ).'</td>';
         $ligne_heures_nrel .= '<td>'.format_duree($r['total_nrel']).( $r['td_nrel'] ? '&nbsp;('.format_duree($r['td_nrel']).')' : '' ).'</td>';
@@ -267,13 +297,13 @@
       $ligne_heures_nrel = ( $total['td_nrel'] ? "<tr><th>Nombre d'heures non relevées (dont séances sans note)</th>$ligne_heures_nrel<td>".format_duree($total['total_nrel']).'&nbsp;('.format_duree($total['td_nrel']).')</td></tr>'
                                                : "<tr><th>Nombre d'heures non relevées</th>$ligne_heures_nrel<td>".format_duree($total['total_nrel']).'</td></tr>' );
       $ligne_heures = ( ($d=$total['td_rel']+$total['td_nrel']) ? "<tr><th>Nombre d'heures total (dont séances sans note)</th>$ligne_heures<td>".format_duree($total['total_rel']+$total['total_nrel']).'&nbsp;('.format_duree($d).')</td></tr>'
-                                                                : "<tr><th>Nombre d'heures total</th>$ligne_heures<td>".format_duree($total['total_rel']).'</td></tr>' );
+                                                                : "<tr><th>Nombre d'heures total</th>$ligne_heures<td>".format_duree($total['total_rel']+$total['total_nrel']).'</td></tr>' );
       // Moyenne globale
       $resultat = $mysqli->query("SELECT LEFT(REPLACE(AVG(IF(note='abs' OR note='nn',NULL,REPLACE(note,',','.'))),'.',','),4) FROM notes WHERE matiere = $mid");
       $r = $resultat->fetch_row();
       $resultat->free();
       echo <<<FIN
-          <th class="colleurs"><span>Total</span></th>
+          <th class="vertical"><span>Total</span></th>
         </tr>
         <tr><th>Nombre d'élèves interrogés</th>$ligne_eleves<td>${total['nb']}</td></tr>
         $ligne_heures
@@ -496,35 +526,21 @@
   // notesperso : élèves déjà notés par le colleur concerné
   // notesautres : élèves déjà notés par les autres colleurs
   // n : nombre de notes du colleur concerné
-  $resultat = $mysqli->query("SELECT s.id, DATE_FORMAT(debut,'%w%Y%m%e') AS debut, DATE_FORMAT(debut,'%d/%m/%Y') AS datedebut, colle, vacances, 
+  $resultat = $mysqli->query("SELECT s.id, DATE_FORMAT(debut,'%w%Y%m%e') AS debut, DATE_FORMAT(debut,'%d/%m/%Y') AS datedebut, colle, v.nom AS vacances, 
                               IFNULL(GROUP_CONCAT(IF(n.colleur=${_SESSION['id']},n.eleve,NULL)),'') AS notesperso,
                               IFNULL(GROUP_CONCAT(IF(n.colleur=${_SESSION['id']},NULL,n.eleve)),'') AS notesautres,
                               COUNT(IF(n.colleur=${_SESSION['id']},1,NULL)) AS n
-                              FROM semaines AS s LEFT JOIN (SELECT * FROM notes WHERE matiere = $mid) AS n ON s.id = n.semaine GROUP BY s.id");
+                              FROM semaines AS s LEFT JOIN vacances AS v ON s.vacances = v.id
+                              LEFT JOIN (SELECT * FROM notes WHERE matiere = $mid) AS n ON s.id = n.semaine GROUP BY s.id");
   $select_semaines = "\n        <option value=\"0\">Choisir une semaine</option>";
   $notesperso = $notesautres = array();
   while ( $r = $resultat->fetch_assoc() )  {
-    switch ( $r['vacances'] )  {
-      case 0:
-        if ( $r['colle'] == 0 )
-          $select_semaines .= "\n        <option disabled data-date=\"${r['datedebut']}\">".format_date($r['debut']).' (pas de colle)</option>';
-        else  {
-          $select_semaines .= "\n        <option value=\"${r['id']}\" data-date=\"${r['datedebut']}\">".format_date($r['debut']).( $r['n'] ? " (${r['n']} notes déjà saisies)" : '').'</option>';
-          $notesperso[$r['id']] = $r['notesperso'];
-          $notesautres[$r['id']] = $r['notesautres'];
-        }
-        break;
-      case 1:
-        $select_semaines .= "\n        <option data-date=\"${r['datedebut']}\" disabled>Vacances de Toussaint</option>";
-        break;
-      case 2:
-        $select_semaines .= "\n        <option data-date=\"${r['datedebut']}\" disabled>Vacances de Noël</option>";
-        break;
-      case 3:
-        $select_semaines .= "\n        <option data-date=\"${r['datedebut']}\" disabled>Vacances d'hiver</option>";
-        break;
-      case 4:
-        $select_semaines .= "\n        <option data-date=\"${r['datedebut']}\" disabled>Vacances de Pâques</option>";
+    if ( $r['colle'] == 0 )
+      $select_semaines .= "\n        <option disabled data-date=\"${r['datedebut']}\">".( $r['vacances'] ?: format_date($r['debut']).' (pas de colle)' ).'</option>';
+    else  {
+      $select_semaines .= "\n        <option value=\"${r['id']}\" data-date=\"${r['datedebut']}\">".format_date($r['debut']).( $r['n'] ? " (${r['n']} notes déjà saisies)" : '').'</option>';
+      $notesperso[$r['id']] = $r['notesperso'];
+      $notesautres[$r['id']] = $r['notesautres'];
     }
   }
   $resultat->free();
diff -urN cahier-de-prepa8.1.1/pages.php cahier-de-prepa9.0.0/pages.php
--- cahier-de-prepa8.1.1/pages.php	2018-10-15 22:07:11.487476927 +0200
+++ cahier-de-prepa9.0.0/pages.php	2019-08-26 01:36:14.656562092 +0200
@@ -12,7 +12,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
@@ -42,7 +42,7 @@
           <option value="1">Invités</option>
           <option value="2">Élèves</option>
           <option value="3">Colleurs</option>
-          <option value="4">Administratifs</option>
+          <option value="4">Lycée</option>
           <option value="5">Professeurs</option>
           <option value="32">Page invisible</option>';
 
@@ -115,7 +115,7 @@
         <select name="protection[]" multiple>$sel_protection
         </select>
       </p>
-      <p class="ligne"><label for="propagation$id">Propager l'accès à chaque information de la page&nbsp;: </label><input type="checkbox" id="propagation$id" name="propagation" value="1"$propagationdisabled></p>
+      <p class="ligne"><label for="propagation$id">Propager ce choix d'accès à chaque information de la page&nbsp;: </label><input type="checkbox" id="propagation$id" name="propagation" value="1"$propagationdisabled></p>
       <p class="ligne"><label for="bandeau$id">Texte de début&nbsp;:</label></p>
       <textarea id="bandeau$id" name="bandeau" rows="2" cols="100" placeholder="Texte qui s'affichera au début de la page">${r['bandeau']}</textarea>$supprinfos
     </form>
diff -urN cahier-de-prepa8.1.1/planning.php cahier-de-prepa9.0.0/planning.php
--- cahier-de-prepa8.1.1/planning.php	2018-10-14 03:16:38.899206997 +0200
+++ cahier-de-prepa9.0.0/planning.php	2019-08-28 16:38:17.284796937 +0200
@@ -12,7 +12,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
@@ -50,12 +50,18 @@
 
 FIN;
 
+// Récupération des vacances
+$resultat = $mysqli->query('SELECT id, nom FROM vacances WHERE id > 0 ORDER BY id');
+$select_vacances = '<option value="0">Période scolaire</option>';
+while ( $r = $resultat->fetch_row() )
+  $select_vacances .= "<option value=\"${r[0]}\">${r[1]}</option>";
+$resultat->free();
 // Récupération et affichage des matières
 $semaine = array('Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi');
 $resultat = $mysqli->query('SELECT id, DATE_FORMAT(debut,\'%w\') AS jour, DATE_FORMAT(debut,\'%d/%m/%Y\') AS debut, IF(colle=1,\' checked\',\'\') AS colle, vacances FROM semaines');
 $mysqli->close();
 while ( $r = $resultat->fetch_assoc() )  {
-  $select = str_replace("\"${r['vacances']}\"","\"${r['vacances']}\" selected",'<option value="0">Période scolaire</option><option value="1">Vacances de Toussaint</option><option value="2">Vacances de Noël</option><option value="3">Vacances d\'hiver</option><option value="4">Vacances de printemps</option>');
+  $select = str_replace("\"${r['vacances']}\"","\"${r['vacances']}\" selected",$select_vacances);
   $r['jour'] = $semaine[$r['jour']];
   echo <<<FIN
           <tr>
@@ -83,8 +89,9 @@
       <li>d'une semaine sans colle (case <em>Colle ou non</em> décochée), qui ne pourra recevoir ni programmes de colles, ni notes de colles.</li>
       <li>d'une semaine de vacances (colonne <em>Vacances</em>) qui ne pourra recevoir ni cahier de texte, ni programmes de colles, ni notes de colles.</li>
     </ul>
-    <p>Les vacances de deux semaines (toutes en fait :-) ) sont donc à marquer deux fois.</p>
+    <p>Les vacances de deux semaines sont donc à marquer deux fois, une fois sur chaque semaine.</p>
     <p>Il est préférable de décocher la case <em>Colle ou non</em> lorsque l'on sait qu'il n'y aura pas de colle, comme souvent en début ou en fin d'année&nbsp;: cela modifie l'affichage des programmes de colles (&laquo;&nbsp;Il n'y a pas de colle cette semaine&nbsp;&raquo; au lieu de &laquo;&nbsp;Le programme de colles de cette semaine n'est pas défini.&nbsp;&raquo;), et évite les erreurs d'écriture des programmes de colles ou de saisie des notes.</p>
+    <p>La validation n'est pas faite à chaque modification, mais une seule fois globalement après unn clic sur le bouton <span class="icon-ok"></span>.</p>
   </div>
 
   <p id="log"></p>
diff -urN cahier-de-prepa8.1.1/prefs.php cahier-de-prepa9.0.0/prefs.php
--- cahier-de-prepa8.1.1/prefs.php	2018-10-14 03:35:17.932343688 +0200
+++ cahier-de-prepa9.0.0/prefs.php	2019-08-28 03:32:27.027490865 +0200
@@ -36,40 +36,28 @@
 debut($mysqli,'Mon compte',$message,$autorisation,'prefs');
 
 // Récupération des données de l'utilisateur
-$resultat = $mysqli->query("SELECT login, nom, prenom, mail, mdp, timeout, mailexp,
+$resultat = $mysqli->query("SELECT nom, prenom, mail, timeout, mailexp,
                             IF(mailcopie,' checked','') AS mailcopie,
-                            IF(mailenvoi,' checked','') AS mailenvoi,
-                            IF(mailliste,' checked','') AS mailliste,
                             IF(permconn > '',' checked','') AS permconn
                             FROM utilisateurs WHERE id = ${_SESSION['id']}");
-$mysqli->close();
 $r = $resultat->fetch_assoc();
 $resultat->free();
+// Autorisation d'envoi de courriel
+$resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+$aut_envoi = $resultat->fetch_row()[0] >> 4*($autorisation-2) & 15;
+$mysqli->close();
 ?>
 
   <div id="icones">
     <a class="icon-aide" title="Aide pour les modifications de vos préférences"></a>
   </div>
 
-  <article>
-    <a class="icon-ferme" title="Fermer ce cadre"></a>
-    <h3>Confidentialité des données</h3>
-    <p>Les données stockées dans ce Cahier de Prépa à propos de vous sont modifiables ici. Il ne s'agit que de données permettant le fonctionnement de ce site. Aucune de ces données ne sera jamais partagée avec une autre entité.</p>
-    <p>Votre mot de passe vous est complètement personnel. Il est chiffré avant son stockage dans la base de données et ne peut donc techniquement être divulgué à personne.</p>
-    <p>Ces données (excepté votre mot de passe) sont aussi accessibles et modifiables par l'ensemble des professeurs de la classe pour permettre le bon fonctionnement du site. Par votre inscription sur ce site, vous autorisez cela et l'administrateur du site à stocker ces informations. Les éventuelles notes de colles que vous pouvez avoir ne sont consultables que par les pages dédiées, pour chaque matière.</p>
-    <p>Pour supprimer votre compte, vous devez le demander aux professeurs de la classe.</p>
-    <p>Le mot de passe associé à votre compte doit être obligatoirement fourni pour toute modification sur cette page. Cela permet d'être sûr que la modification n'est pas réalisée par quelqu'un d'autre.</p>
-    <p>D'autres données de connexion sont stockées pour le service du site&nbsp;: les connexions aux comptes (avec identifiant et adresse IP) et les modifications de la base de données sont consignées pour réparer les éventuelles erreurs. Ces données sont supprimées en fin d'année scolaire. Ces données ne sont exploitées qu'en cas de besoin technique et ne sont pas partagées.</p>
-  </article>
-
   <article data-id="prefsperso|1">
     <h3 class="edition">Mon identité</h3>
     <a class="icon-ok noreload" title="Valider les modifications"></a>
     <form>
       <p class="ligne"><label for="prenom">Prénom&nbsp;: </label><input type="text" id="prenom" name="prenom" value="<?php echo $r['prenom']; ?>" size="50"></p>
       <p class="ligne"><label for="nom">Nom&nbsp;: </label><input type="text" id="nom" name="nom" value="<?php echo $r['nom']; ?>" size="50"></p>
-      <p class="ligne"><label for="mail1">Adresse électronique&nbsp;: </label><input type="email" id="mail1" name="mail1" value="<?php echo $r['mail']; ?>" size="50"></p>
-      <p class="ligne"><label for="mail2">Confirmation&nbsp;: </label><input type="email" id="mail2" name="mail2" value="" size="50"></p>
       <p class="ligne"><label for="mdp_1">Mot de passe&nbsp;: </label><input type="password" id="mdp_1" name="mdp" value=""></p>
       <p>Le mot de passe actuel doit être obligatoirement fourni pour toute modification.</p>
     </form>
@@ -77,7 +65,7 @@
 
   <article data-id="prefsperso|2">
     <h3 class="edition">Mon mot de passe</h3>
-    <a class="icon-ok noreload" title="Valider les modifications"></a>
+    <a class="icon-ok" title="Valider les modifications"></a>
     <form>
       <p class="ligne"><label for="mdp_2">Mot de passe actuel&nbsp;: </label><input type="password" id="mdp_2" name="mdp" value=""></p>
       <p class="ligne"><label for="mdp1">Nouveau mot de passe&nbsp;: </label><input type="password" id="mdp1" name="mdp1" value=""></p>
@@ -86,46 +74,41 @@
   </article>
 
   <article data-id="prefsperso|3">
-    <h3 class="edition">Ma connexion</h3>
-    <a class="icon-ok noreload" title="Valider les modifications"></a>
+    <h3 class="edition">Mon adresse électronique</h3>
+    <a class="icon-ok" title="Valider les modifications"></a>
+    <p>Un code de confirmation va être envoyé par courriel à la nouvelle adresse.</p>
     <form>
-      <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" id="login" name="login" value="<?php echo $r['login']; ?>" size="50"></p>
-      <p class="ligne"><label for="permconn">Conserver ma connexion sur cette machine&nbsp;: </label><input type="checkbox" id="permconn" name="permconn" value="1"<?php echo $r['permconn']; ?>></p>
-      <p class="ligne"><label for="timeout">Durée avant déconnexion&nbsp;: </label><input type="text" id="timeout" name="timeout" value="<?php echo $r['timeout']; ?>" size="3"></p>
-      <p class="ligne"><label for="mdp_3">Mot de passe actuel&nbsp;: </label><input type="password" id="mdp_3" name="mdp" value=""></p>
+      <p class="ligne"><label for="mail">Adresse électronique&nbsp;: </label><input type="email" id="mail" name="mail" value="<?php echo $r['mail']; ?>" size="50"></p>
+      <p class="ligne" style="display: none;"><label for="confirmation">Code de confirmation&nbsp;: </label><input type="text" id="confirmation" name="confirmation" value="" size="50" disabled></p>
+      <p class="ligne"><label for="mdp_3">Mot de passe&nbsp;: </label><input type="password" id="mdp_3" name="mdp" value=""></p>
       <p>Le mot de passe actuel doit être obligatoirement fourni pour toute modification.</p>
     </form>
   </article>
-<?php
-// Cas d'envoi de mail des élèves : uniquement si validé par un professeur
-if ( ( $autorisation == 2 ) && $_SESSION['mailenvoi'] )  {
-?>
 
   <article data-id="prefsperso|4">
-    <h3 class="edition">Mes envois de courriel</h3>
+    <h3 class="edition">Ma connexion</h3>
     <a class="icon-ok noreload" title="Valider les modifications"></a>
     <form>
-      <p class="ligne"><label for="mailexp">Nom d'expéditeur&nbsp;: </label><input type="text" id="mailexp" name="mailexp" value="<?php echo $r['mailexp']; ?>" size="50"></p>
-      <p class="ligne"><label for="mailcopie">Recevoir une copie des courriels envoyés&nbsp;: </label><input type="checkbox" id="mailcopie" name="mailcopie" value="1"<?php echo $r['mailcopie']; ?>></p>
+      <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" id="login" name="login" value="<?php echo $_SESSION['login']; ?>" size="50"></p>
+      <p class="ligne"><label for="permconn">Conserver ma connexion sur cette machine&nbsp;: </label><input type="checkbox" id="permconn" name="permconn" value="1"<?php echo $r['permconn']; ?>></p>
+      <p class="ligne"><label for="timeout">Durée avant déconnexion&nbsp;: </label><input type="text" id="timeout" name="timeout" value="<?php echo $r['timeout']; ?>" size="3"></p>
       <p class="ligne"><label for="mdp_4">Mot de passe actuel&nbsp;: </label><input type="password" id="mdp_4" name="mdp" value=""></p>
       <p>Le mot de passe actuel doit être obligatoirement fourni pour toute modification.</p>
     </form>
   </article>
 <?php
-}
-// Cas des comptes colleur/administration/professeur
-elseif ( $autorisation > 2 )  {
+// Préférences d'envoi des mails seulement si autorisé globalement
+
+if ( $aut_envoi )  {
 ?>
 
-  <article data-id="prefsperso|4">
+  <article data-id="prefsperso|5">
     <h3 class="edition">Mes envois de courriel</h3>
     <a class="icon-ok noreload" title="Valider les modifications"></a>
     <form>
-      <p class="ligne"><label for="mailenvoi">S'autoriser l'envoi de courriel&nbsp;: </label><input type="checkbox" id="mailenvoi" name="mailenvoi" value="1"<?php echo $r['mailenvoi']; ?>></p>
-      <p class="ligne"><label for="mailexp">Nom d'expéditeur&nbsp;: </label><input type="text" id="mailexp" name="mailexp" value="<?php echo $r['mailexp']; ?>" size="50"></p>
+      <p class="ligne"><label for="mailexp">Nom affiché comme expéditateur/destinataire de courriel&nbsp;: </label><input type="text" id="mailexp" name="mailexp" value="<?php echo $r['mailexp']; ?>" size="50"></p>
       <p class="ligne"><label for="mailcopie">Recevoir une copie des courriels envoyés&nbsp;: </label><input type="checkbox" id="mailcopie" name="mailcopie" value="1"<?php echo $r['mailcopie']; ?>></p>
-      <p class="ligne"><label for="mailliste">Apparaître dans la liste visible des élèves&nbsp;: </label><input type="checkbox" id="mailliste" name="mailliste" value="1"<?php echo $r['mailliste']; ?>></p>
-      <p class="ligne"><label for="mdp_4">Mot de passe actuel&nbsp;: </label><input type="password" id="mdp_4" name="mdp" value=""></p>
+      <p class="ligne"><label for="mdp_5">Mot de passe actuel&nbsp;: </label><input type="password" id="mdp_5" name="mdp" value=""></p>
       <p>Le mot de passe actuel doit être obligatoirement fourni pour toute modification.</p>
     </form>
   </article>
@@ -133,20 +116,38 @@
 }
 ?>
 
+  <article id="rgpd">
+    <h2>Données personnelles et compatibilité RGPD</h2>
+    <p>Les informations recueillies par chaque Cahier de Prépa font l'objet d'un traitement informatique destiné à assurer le fonctionnement du Cahier (envoi de mail, affichage des coordonnées pour les professeurs, inscription des notes de colle). Seules sont stockées les informations strictement nécessaires au bon fonctionnement du service : nom, prénom et adresse électronique. Toutes ces données sont visibles et modifiables ci-dessus.</p>
+    <p>Vos données, à l'exception de votre mot de passe, sont aussi accessibles et modifiables par l'ensemble des professeurs de la classe et l'administration de votre lycée, pour permettre le bon fonctionnement du Cahier. Par votre inscription sur ce Cahier, vous autorisez cela ainsi que le stockage de ces informations par l'administrateur du site. Les éventuelles notes de colles des élèves ne sont consultables que par les personnes concernées (élève, colleur, professeur de la matière, administration du lycée), sur les pages dédiées.</p>
+    <p>Votre mot de passe vous est complètement personnel. Il est chiffré avant son stockage dans la base de données et ne peut donc techniquement être divulgué à personne.</p>
+    <p>La suppression de votre compte doit passer par les professeurs de la classe. Le fonctionnement de la classe peut néanmoins nécessiter la conservation de votre compte au moins jusqu'à la fin de l'année scolaire.</p>
+    <p>Les adresses IP ne sont pas conservées dans la base de données, mais chaque action de modification de la base conduit à l'écriture de l'adresse IP utilisée dans un journal.</p>
+    <p>Aucun cookie n'est utilisé pour stocker des données. Seul un cookie de session (identifiant permettant de conserver l'identification d'une page à l'autre) est utilisé lorsque vous vous connectez.</p>
+    <p>Conformément à la <a href="https://www.cnil.fr/fr/loi-78-17-du-6-janvier-1978-modifiee">loi «&nbsp;informatique et libertés&nbsp;» du 6 janvier 1978 modifiée</a>, vous disposez d'un <a href="https://www.cnil.fr/fr/le-droit-dacces">droit d'accès</a> et d'un <a href="https://www.cnil.fr/fr/le-droit-de-rectification">droit de rectification</a> des informations qui vous concernent. Vous pouvez accèder aux informations vous concernant en vous connectant sur votre Cahier de Prépa ou en vous adressant à <a href="mailto:contact@cahier-de-prepa.fr">contact@cahier-de-prepa.fr</a>. Vous pouvez également, pour des motifs légitimes, <a href="https://www.cnil.fr/fr/le-droit-dopposition">vous opposer au traitement des données vous concernant</a>.</p>
+    <p>Aucune de ces données ne sera communiquée à une autre organisation. Cahier de Prépa est un service gratuit offert par un professeur de CPGE bénévole, sans publicité et sans vente de données.</p>
+    <p>Le traitement des données réalisé par Cahier de Prépa est compatible avec le Réglement Général sur la Protection des Données.</p>
+  </article>
+
   <div id="aide-page">
     <h3>Aide et explications</h3>
-    <p>Il est possible ici de modifier vos préférences. Une fois modifié, un formulaire est à validé par un clic sur le bouton <span class="icon-ok"></span>.</p>
-    <p>Afin d'éviter les usurpations de compte, il est nécessaire de taper son mot de passe pour toute modification.</p>
-    <h4>Modification de l'identité&nbsp;: nom, prénom, adresse électronique</h4>
-    <p>Si l'on souhaite modifier l'adresse électronique, il faut la saisir deux fois afin d'éviter les fautes de frappes.</p>
-    <p>Afin d'éviter les usurpations de compte, il est nécessaire de taper son mot de passe pour toute modification.</p>
-    <p>L'adresse électronique ne sera pas modifiée si un autre compte contient déjà la nouvelle valeur saisie.</p>
-    <p>Il est possible de ne modifier que le prénom ou le nom sans modifier l'adresse électronique&nbsp;: il n'est alors pas nécessaire de saisir une deuxième fois l'adresse électronique.</p>
-    <p>L'adresse électronique peut servir pour envoyer ou recevoir des courriels, en fonction du réglage choisi par l'équipe pédagogique.</p>
+    <p>Il est possible ici de modifier vos préférences. Une fois modifié, un formulaire est à validé par un clic sur le bouton <span class="icon-ok"></span> correspondant.</p>
+    <p>Afin d'éviter les modifications de compte frauduleuses, il est nécessaire de taper son mot de passe pour toute modification.</p>
+    <h4>Modification de l'identité&nbsp;: nom, prénom</h4>
+    <p>Il est possible de modifier votre <em>nom</em> ou votre <em>prénom</em>. Ils sont utilisés pour tous les affichages nécessitant de vous identifier&nbsp;: tableaux d'administration du Cahier de Prépa et tableaux de notes de colles.</p>
+    <h4>Modification du mot de passe</h4>
+    <p>Votre <em>mot de passe</em> est stocké chiffré dans la base de données du Cahier de Prépa. Il n'est jamais manipulé sans être préalablement chiffré. Vous avez intérêt à utiliser un mot de passe qui vous est personnel, et à éviter les mots de passe faciles à deviner tels que «&nbsp;arnaud75&nbsp;» ou «&nbsp;goldorak&nbsp;» (reprenant des mots entiers et une passion, une identité, une adresse...). Vous avez intérêt aussi à utiliser le même mot de passe sur tous les Cahiers de Prépa où vous pourriez vous connecter.</p>
+    <h4>Modification de l'adresse électronique</h4>
+    <p>Pour modifier votre <em>adresse électronique</em>, vous devrez saisir cette nouvelle adresse et récupérer un <em>code de confirmation</em> de 8 caractères envoyé par courriel à cette adresse. Ce code est valable entre 15 et 75 minutes. La demande s'annule automatiquement si vous ne donnez pas suite. Vous pouvez demander à recevoir ce courriel autant de fois que vous le souhaitez.</p>
+    <p>Il n'est pas possible d'affecter la même adresse électronique à deux comptes différents sur un même Cahier de Prépa.</p>
+    <p>L'adresse électronique sert à envoyer ou recevoir des courriels, en fonction du réglage choisi par l'équipe pédagogique.</p>
     <h4>Modification des paramètres de connexion</h4>
-    <p>Votre identifiant est initialement de la forme &laquo;&nbsp;jdupont&nbsp;&raquo;. Vous pouvez le modifier, à condition de ne pas demander un identifiant déjà existant dans la base.</p>
+    <p>Votre <em>identifiant</em> est initialement de la forme &laquo;&nbsp;jdupont&nbsp;&raquo;. Vous pouvez le modifier, à condition de ne pas demander un identifiant déjà existant dans la base.</p>
     <p>La <em>durée avant connexion</em> est la durée en secondes au bout de laquelle votre session sera effacée sur le serveur, et une reconnexion sera nécessaire. C'est une sécurité si vous oubliez de vous déconnecter alors que vous êtes sur un ordinateur ouvert au public. La valeur par défaut est 900s, soit 15 minutes.</p>
-    <p>La case à cocher <em>Conserver ma connexion sur cette machine</em> est au contraire utile lorsque vous êtes sur une machine personnelle, comme votre téléphone. Cocher cette case permet de ne pas avoir besoin de se connecter systématiquement. Le mot de passe ne sera demandé que pour l'affichage de données nomminatives ou de modifications importantes.</p>
+    <p>La case à cocher <em>Conserver ma connexion sur cette machine</em> est au contraire utile lorsque vous êtes sur une machine personnelle comme votre téléphone, votre ordinateur personnel ou un ordinateur en réseau si vous faites bien attention à ne jamais laisser votre session ouverte sans vous ! Cocher cette case permet de ne pas avoir besoin de se connecter systématiquement. Le mot de passe ne sera demandé que pour l'affichage de données nomminatives ou de modifications importantes.</p>
+    <h4>Modification des paramètres d'envoi de courriel</h4>
+    <p>Ce réglage n'est disponible que si vous avez la possibilité d'envoyer des courriels via ce Cahier de Prépa. Vous pouvez alors régler votre <em>nom affiché comme expéditeur</em>, qui s'affiche notamment devant le destinataire lorsqu'il reçoit et lit votre courriel.</p>
+    <p>La case à cocher <em>Recevoir une copie des courriels envoyés</em> n'est qu'une valeur par défaut. Une case à cocher se trouve sur la page de <a href="mail">rédaction des courriels</a>, vous permettant de modifier au cas par cas ce réglage. Il permet de recevoir sur son adresse électronique une copie des courriels envoyés, afin de l'archiver par exemple.</p>
   </div>
 
   <p id="log"></p>
diff -urN cahier-de-prepa8.1.1/README.php cahier-de-prepa9.0.0/README.php
--- cahier-de-prepa8.1.1/README.php	2015-10-27 15:08:28.485048620 +0100
+++ cahier-de-prepa9.0.0/README.php	2019-08-27 00:50:13.085627091 +0200
@@ -11,7 +11,7 @@
 
 Plus d'informations sont disponibles sur <http://cahier-de-prepa.fr>.
 
-Copyright Cyril Ravat, <contact@cahier-de-prepa.fr> (2009-2013) 
+Copyright Cyril Ravat, <contact@cahier-de-prepa.fr> (2009-2019) 
 
 Ce logiciel est régi par la licence CeCILL soumise au droit français et
 respectant les principes de diffusion des logiciels libres. Vous pouvez
diff -urN cahier-de-prepa8.1.1/recent.php cahier-de-prepa9.0.0/recent.php
--- cahier-de-prepa8.1.1/recent.php	1970-01-01 01:00:00.000000000 +0100
+++ cahier-de-prepa9.0.0/recent.php	2019-08-26 10:38:57.111433388 +0200
@@ -0,0 +1,189 @@
+<?php
+// Sécurité
+define('OK',1);
+// Configuration
+include('config.php');
+// Fonctions
+include('fonctions.php');
+
+////////////////////////////////////////////////
+// Validation de la requête : matière et type //
+////////////////////////////////////////////////
+
+// Recherche de la matière concernée, variable $matiere
+// Génération du sélecteur de matières
+// Si $_REQUEST['cle'] existe, on la cherche dans les matières disponibles.
+$mysqli = connectsql();
+$select_matieres = '
+      <option value="general">Pas de matière associée</option>';
+$matieres = array('0'=>'general');
+$resultat = $mysqli->query('SELECT id, cle, nom FROM matieres WHERE '.( $autorisation ? "FIND_IN_SET(id,'${_SESSION['matieres']}')" : '1' ));
+if ( $resultat->num_rows )  {
+  while ( $r = $resultat->fetch_assoc() )  {
+    $matieres[$r['id']] = $r['cle'];
+    $select_matieres .= "\n      <option value=\"${r['cle']}\">${r['nom']}</option>";
+  }
+  $resultat->free();
+  if ( isset($_REQUEST['matiere']) && in_array($cle = $_REQUEST['matiere'],$matieres) )  {
+    $mid = array_search($cle,$matieres);
+    $select_matieres = str_replace("\"$cle\"","\"$cle\" selected",$select_matieres);
+  }
+}
+// Recherche du type et génération du sélecteur de type
+$select_types = <<<FIN
+
+      <option value="infos">Les informations</option>
+      <option value="colles">Les programmes de colles</option>
+      <option value="docs">Les documents</option>
+      <option value="agenda">L'agenda</option>
+FIN;
+$types = array('infos','colles','docs','agenda');
+if ( isset($_REQUEST['type']) && in_array($cle = $_REQUEST['type'],$types) )  {
+  $tid = 1+array_search($cle,$types);
+  $select_types = str_replace("\"$cle\"","\"$cle\" selected",$select_types);
+}
+// Fabrication de la requête
+if ( $autorisation )  
+  $requete = '('.requete_protection($autorisation).') AND '.( isset($mid) ? "matiere = $mid" : "FIND_IN_SET(matiere,'${_SESSION['matieres']}')" );
+else 
+  $requete = 'protection = 0'.( isset($mid) ? " AND matiere = $mid" : '');
+if ( isset($tid) )
+  $requete .= " AND type = $tid";
+// Demande de recherche sur les titres et textes
+$recherche = '';
+if ( isset($_REQUEST['recherche']) && $_REQUEST['recherche'] )
+  $requete .= ' AND ( titre LIKE \'%'.$mysqli->real_escape_string($recherche = htmlspecialchars($_REQUEST['recherche'])).'%\') OR ( texte LIKE \'%'.$mysqli->real_escape_string($recherche).'%\') ';
+
+//////////////
+//// HTML ////
+//////////////
+debut($mysqli,'Derniers contenus',$message,$autorisation,'recents');
+
+// Liste des icônes pour affichage
+$icones = array(
+  'pdf' => '-pdf',
+  'doc' => '-doc', 'odt' => '-doc', 'docx' => '-doc',
+  'xls' => '-xls', 'ods' => '-xls', 'xlsx' => '-xls',
+  'ppt' => '-ppt', 'odp' => '-ppt', 'pptx' => '-ppt',
+  'jpg' => '-jpg', 'jpeg' => '-jpg', 'png' => '-jpg', 'gif' => '-jpg', 'svg' => '-jpg', 'tif' => '-jpg', 'tiff' => '-jpg', 'bmp' => '-jpg', 'ps' => '-jpg', 'eps' => '-jpg',
+  'mp3' => '-mp3', 'ogg' => '-mp3', 'oga' => '-mp3', 'wma' => '-mp3', 'wav' => '-mp3', 'ra' => '-mp3', 'rm' => '-mp3',
+  'mp4' => '-mp4', 'avi' => '-mp4', 'mpeg' => '-mp4', 'mpg' => '-mp4', 'wmv' => '-mp4', 'mp4' => '-mp4', 'ogv' => '-mp4', 'qt' => '-mp4', 'mov' => '-mp4', 'mkv' => '-mp4', 'flv' => '-mp4',
+  'zip' => '-zip', 'rar' => '-zip', '7z' => '-zip',
+  'py' => '-py', 'exe' => '-py', 'sh' => '-py', 'ml' => '-py', 'mw' => '-py',
+  'db' => '-db', 'db3' => '-db', 'sqlite' => '-db',
+  'sql' => '-sql',
+  'txt' => '', 'rtf' => '', '' => ''
+);
+
+// Affichage des éléments récents à afficher
+$resultat = $mysqli->query("SELECT type, UNIX_TIMESTAMP(publi) AS publi, UNIX_TIMESTAMP(maj) AS maj, titre, lien, texte FROM recents
+                            WHERE $requete AND ( DATEDIFF(NOW(),publi) < 180 OR DATEDIFF(NOW(),maj) < 180 ) 
+                            ORDER BY IF(maj>0,maj,publi) DESC LIMIT 100");
+if ( $resultat->num_rows || isset($mid) || isset($tid) || isset($_REQUEST['recherche']) )  {
+
+  // Barre de recherche
+  echo <<<FIN
+  <p id="rechercherecent" class="topbarre">
+    <select id="type" onchange="window.location='?type='+this.value+'&amp;matiere='+$(this).next().val();">
+      <option value="tout">Filtrer par type</option>$select_types
+    </select>
+    <select id="matiere" onchange="window.location='?type='+$(this).prev().val()+'&amp;matiere='+this.value;">
+      <option value="tout">Filtrer par matière</option>$select_matieres
+    </select>
+    <span class="icon-recherche" onclick="if ( !$(this).prev().is(':visible')) $(this).prev().show(); else window.location='?recherche='+$(this).prev().val();"></span>
+    <input type="text" value="$recherche" onchange="window.location='?recherche='+this.value;" title="Rechercher dans les titres et textes des contenus">
+  </p>
+
+FIN;
+
+  if ( $resultat->num_rows )  {
+    while ( $r = $resultat->fetch_assoc() )  {
+      $d = str_replace(' à 00h00','',date('d/m à H\hi',$r['maj'] ?: $r['publi']));
+      // Icône et modification spécifique au type
+      switch ( $r['type'] )  {
+        case 1:
+          $icone = '<span class="icon-infos"></span>';
+          break;
+        case 2:
+          $icone = '<span class="icon-colles"></span>';
+          break;
+        case 3:
+          $icone = '<span class="icon-doc'.$icones[substr(strtok($r['texte'],'|'),1)].'"></span>';
+          $r['texte'] = '<p>Document de '.strtok('|').', dans <a href="docs?rep='.strtok('|').'">'.strtok('|').'</a></p>';
+          break;
+        case 4 :
+          $icone = '<span class="icon-agenda"></span>';
+      }
+      if ( $r['maj'] )  {
+        $r['titre'] .= ' (mise à jour)';
+        $d .= ' (publication initiale le '.str_replace(' à 00h00','',date('d/m à H\hi',$r['publi'])).')';
+      }
+      echo <<<FIN
+    <article class="recents">
+      <h3>$icone&nbsp;<a href="${r['lien']}">${r['titre']}</a></h3>
+      <p class="publi">Publication le $d</p>
+      <div>${r['texte']}</div>
+    </article>
+
+
+FIN;
+    }
+    $resultat->free();
+  }
+  
+  // Recherche sans résultat
+  else 
+    echo <<<FIN
+    <article>
+      <h2>Aucun résultat n'a été trouvé pour cette recherche.</h2>
+    </article>
+
+
+FIN;
+}
+else
+  echo <<<FIN
+    <article>
+      <h2>Aucun nouveau contenu n'a été ajouté récemment.</h2>
+    </article>
+
+
+FIN;
+?>
+
+  <div id="aide-rss">
+    <h3>Flux RSS</h3>
+    <p>Un flux RSS est une page web spécifique dont le contenu est mis à jour de façon permanente. Sa forme n'est pas très lisible directement dans votre navigateur, mais elle permet de récupérer le contenu d'un fil d'actualité à l'aide d'un logiciel prévu pour lire ce genre de page. Le logiciel va recharger tout seul la page à une période de quelques minutes et vous prévenir directement des nouveautés.</p>
+    <p>Votre navigateur peut prendre en charge les flux RSS&nbsp;: <a href="https://firefox.com">Firefox</a> le fait nativement, <a href="https://www.google.fr/chrome/">Chrome</a> a besoin d'une  
+    <a href="https://chrome.google.com/webstore/detail/rss-subscription-extensio/nlbjncdgjeocebhnmkbbbdekmmmcbfjd">extension</a> pour le faire.</p>
+    <p>Un grand nombre d'applications pour Android et iOS existent, il faut taper «&nbsp;RSS&nbsp;» ou «&nbsp;feed&nbsp;» dans votre magasin d'application. Pour Android, l'application gratuite, sans pub <em>et libre</em> <a href="https://play.google.com/store/apps/details?id=net.frju.flym">Flym</a> est un très bon choix.</p>
+
+<?php
+if ( $autorisation )  {
+  if ( !is_dir($rep = 'rss/'.substr(sha1("?!$mdp|$autorisation|${_SESSION['matieres']}"),0,20)) )
+    rss($mysqli,explode(',',$_SESSION['matieres'])[1],32-(1<<$autorisation));
+?>
+
+    <p>Le flux RSS spécifique à votre compte est disponible à l'adresse</p>
+    <p class="centre"><a href="<?php echo $rep; ?>/rss.xml">http://<?php echo "$domaine$chemin$rep"; ?>/rss.xml</a></p>
+    <p>Ce flux liste l'ensemble des éléments que vous pouvez voir sur ce Cahier de Prépa. Cette adresse donne directement accès aux informations sur le site&nbsp;: merci de ne pas la divulguer à des personnes n'ayant pas d'accès au site.</p>
+  </div>
+
+<?php
+}
+else  {
+  if ( !is_dir($rep = 'rss/'.substr(sha1("?!$mdp|0|toutes"),0,20)) )
+    rss($mysqli,0,0);
+?>
+
+    <p>Le flux RSS public est disponible à l'adresse</p>
+    <p class="centre"><a href="<?php echo $rep; ?>/rss.xml">http://<?php echo "$domaine$chemin$rep"; ?>/rss.xml</a></p>
+    <p>Ce flux contient uniquement les éléments visibles sans identification sur ce Cahier de Prépa. Si vous avez un compte ici, vous avez intérêt à vous connecter pour connaître l'adresse du flux correspondant à tout ce à quoi vous pouvez accéder normalement.</p>
+  </div>
+
+<?php
+}
+
+$mysqli->close();
+fin(false,false);
+?>
diff -urN cahier-de-prepa8.1.1/recup.php cahier-de-prepa9.0.0/recup.php
--- cahier-de-prepa8.1.1/recup.php	2018-10-16 12:36:04.191711083 +0200
+++ cahier-de-prepa9.0.0/recup.php	2019-08-25 01:55:41.119368442 +0200
@@ -11,21 +11,15 @@
   exit('{"etat":"nok","message":"Accès non autorisé"}');
 
 // Récupération de l'action
-if ( !isset($_REQUEST['action']) || !in_array($action = $_REQUEST['action'],array('prefs','docs')) )
+if ( !isset($_REQUEST['action']) || !in_array($action = $_REQUEST['action'],array('prefs','docs','compteglobal')) )
   exit('{"etat":"nok","message":"Mauvais paramètrage"}');
 
-// Accès professeur uniquement
-if ( $autorisation < 5 )
-  exit( strlen($message) ? $message : '{"etat":"nok","message":"Accès interdit"}' );
-
-// Connexion à la base de données
-$mysqli = connectsql(false);
-
 ///////////////////////////////////////////////
 // Récupération des répertoires et documents //
 ///////////////////////////////////////////////
-if ( $action == 'docs' )  {
+if ( ( $autorisation == 5 ) && ( $action == 'docs' ) )  {
 
+  $mysqli = connectsql(false);
   $mats = '<option value="-1">[Choisissez une matière]</option>';
   $reps = array( -1 =>'<option value="-1">[Choisissez une matière]</option>');
   $docs = array( -1 => '<option value="0">[Choisissez une matière]</option>', 0 => '<option value="0">[Choisissez un répertoire]</option>' );
@@ -51,7 +45,6 @@
     }
     $resultat->free();
   }
-  $mysqli->close();
   exit(json_encode(array('recupok'=>1,'mats'=>$mats,'reps'=>$reps,'docs'=>$docs)));
 
 }
@@ -59,12 +52,12 @@
 ///////////////////////////////////////////////
 // Récupération des données d'un utilisateur //
 ///////////////////////////////////////////////
-elseif ( ( $action == 'prefs' ) && connexionlight() )  {
+elseif ( ( $autorisation == 5 ) && ( $action == 'prefs' ) && connexionlight() )  {
 
   // Vérification que l'identifiant est valide
+  $mysqli = connectsql(false);
   if ( isset($_REQUEST['id']) && ctype_digit($id = $_REQUEST['id']) )  {
-    $resultat = $mysqli->query("SELECT nom, prenom, login, matieres, mail as mail1, (LENGTH(mdp)=40) AS valide, (LEFT(mdp,1)='*') AS demande, (LENGTH(mdp)=1) AS invitation, autorisation, mailenvoi, mailexp, mailcopie, mailliste FROM utilisateurs WHERE id = $id");
-    $mysqli->close();
+    $resultat = $mysqli->query("SELECT nom, prenom, login, matieres, mail as mail1, (LENGTH(mdp)=40) AS valide, (LEFT(mdp,1)='*') AS demande, (LENGTH(mdp)=1) AS invitation, autorisation, mailexp, mailcopie FROM utilisateurs WHERE id = $id");
     if ( $resultat->num_rows )  {
       $r = $resultat->fetch_assoc();
       $resultat->free();
@@ -74,9 +67,11 @@
       $r['demande'] = intval($r['demande']);
       $r['invitation'] = intval($r['invitation']);
       $r['autorisation'] = intval($r['autorisation']);
-      $r['mailenvoi'] = intval($r['mailenvoi']);
       $r['mailcopie'] = intval($r['mailcopie']);
-      $r['mailliste'] = intval($r['mailliste']);
+      // Récupération des autorisations d'envoi
+      $resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+      $r['mailenvoi'] = ( $r['autorisation'] > 1 ) ? intval(( $resultat->fetch_row()[0] >> 4*($r['autorisation']-2) & 15 ) > 0) : 0;
+      $resultat->free();
       $r['mail2'] = '';
       $r['etat'] = 'recupok';
       exit(json_encode($r));
@@ -85,4 +80,38 @@
   exit('{"etat":"nok","message":"Identifiant non valide"}');
 
 }
+
+///////////////////////////////////////////////
+// Récupération des données d'un utilisateur //
+///////////////////////////////////////////////
+elseif ( ( $autorisation > 1 ) && ( $action == 'compteglobal' ) && $interfaceglobale )  {
+
+  // $_SESSION['compteglobal'] contient l'identifiant du compte à utiliser
+  // La deuxième partie de la requête sert de vérification : 
+  //  * compte contenant une connexion vers cet utilisateur de ce Cahier
+  //  * compte contenant au moins une autre connexion 
+  $mysqli = connectsql(false,$interfaceglobale);
+  $resultat = $mysqli->query("SELECT connexions FROM comptes 
+                              WHERE id = ${_SESSION['compteglobal']} 
+                                AND FIND_IN_SET((SELECT id FROM cahiers WHERE rep = TRIM(BOTH '/' FROM '${GLOBALS['chemin']}'))*1000+${_SESSION['id']}, connexions)
+                                AND LOCATE(',',connexions)");
+  if ( $resultat->num_rows )  {
+    $cahiers = implode(',', array_filter(array_map( function($v){return ($v>0)?intdiv($v,1000):false;}, explode(',',$resultat->fetch_row()[0]) )) );
+    $resultat->free();
+    $resultat = $mysqli->query("SELECT rep, CONCAT(classe,' - ',nom,' (',ville,') ') AS classe
+                                FROM cahiers LEFT JOIN lycees ON lycee = lycees.id
+                                WHERE FIND_IN_SET(cahiers.id,'$cahiers') ORDER BY FIND_IN_SET(cahiers.id,'$cahiers')");
+    $reps = array();
+    while ( $r = $resultat->fetch_assoc() ) 
+      if ( "/${r['rep']}/" != $chemin )
+        $reps[$r['rep']] = $r['classe'];
+    $resultat->free();
+    $mysqli->close();
+    exit(json_encode(array('etat'=>'recupok','cahiers'=>$reps)));
+  }
+  exit('{"etat":"nok","message":"Identifiant non valide"}');
+}
+
+// Réponse par défaut
+exit( strlen($message) ? $message : '{"etat":"nok","message":"Accès interdit"}' );
 ?>
diff -urN cahier-de-prepa8.1.1/relevenotes.php cahier-de-prepa9.0.0/relevenotes.php
--- cahier-de-prepa8.1.1/relevenotes.php	2018-10-30 04:42:59.700112066 +0100
+++ cahier-de-prepa9.0.0/relevenotes.php	2019-08-05 01:45:34.379177853 +0200
@@ -12,7 +12,7 @@
 
 // Accès aux comptes administratifs connectés uniquement. Redirection pour les autres.
 if ( $autorisation != 4 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
diff -urN cahier-de-prepa8.1.1/rss.php cahier-de-prepa9.0.0/rss.php
--- cahier-de-prepa8.1.1/rss.php	2016-08-29 22:42:42.461399848 +0200
+++ cahier-de-prepa9.0.0/rss.php	1970-01-01 01:00:00.000000000 +0100
@@ -1,54 +0,0 @@
-<?php
-// Sécurité
-define('OK',1);
-// Configuration
-include('config.php');
-// Fonctions
-include('fonctions.php');
-
-$mysqli = connectsql();
-
-//////////////
-//// HTML ////
-//////////////
-debut($mysqli,'Flux RSS',$message,$autorisation,'rss');
-?>
-  <article>
-    <p>Un flux RSS est une page web dont le contenu est mis à jour de façon permanente. Il permet de récupérer le contenu d'un fil d'actualité à l'aide d'un logiciel prévu pour lire ce genre de page. Firefox les prend en charge nativement, et un certain nombre d'applications existent sur Android et iOS (tapez simplement «&nbsp;RSS&nbsp;» dans la zone de recherche du magasin d'applications).</p>
-  </article>
-
-<?php
-if ( !$autorisation )  {
-  // On vérifie que les flux RSS que l'utilisateur peut souhaiter voir existent.
-  if ( !is_dir($rep = 'documents/rss/'.sha1("?!${base}0|toutes")) )
-    rss($mysqli,array(0));
-?>
-
-  <article>
-    <h3>Le flux RSS public est disponible à l'adresse</h3>
-    <p><a href="<?php echo $rep; ?>/rss.xml">http://<?php echo "$site/$rep"; ?>/rss.xml</a></p>
-    <p>Ce flux contient uniquement les éléments visibles sans identification sur ce Cahier de Prépa.</p>
-    <p>Si vous avez un compte ici, vous avez intérêt à vous connecter pour obtenir le flux correspondant à tout ce à quoi vous pouvez accéder normalement.</p>
-  </article>
-
-<?php
-}
-else  {
-  // On vérifie que les flux RSS que l'utilisateur peut souhaiter voir existent.
-  if ( !is_dir($rep = 'documents/rss/'.sha1("?!$base$autorisation|${_SESSION['matieres']}")) )
-    rss($mysqli,array(explode(',',$_SESSION['matieres'])[0]));
-?>
-
-  <article>
-    <h3>Le flux RSS spécifique à votre compte est disponible à l'adresse</h3>
-    <p><a href="<?php echo $rep; ?>/rss.xml">http://<?php echo "$site/$rep"; ?>/rss.xml</a></p>
-    <p>Ce flux liste l'ensemble des éléments que vous pouvez voir sur ce Cahier de Prépa.</p>
-    <p>Cette adresse donne directement accès aux informations sur le site&nbsp;: merci de ne pas la divulguer à des personnes n'ayant pas d'accès au site.</p>
-  </article>
-
-<?php
-}
-
-$mysqli->close();
-fin(false,false);
-?>
diff -urN cahier-de-prepa8.1.1/utilisateurs-mails.php cahier-de-prepa9.0.0/utilisateurs-mails.php
--- cahier-de-prepa8.1.1/utilisateurs-mails.php	1970-01-01 01:00:00.000000000 +0100
+++ cahier-de-prepa9.0.0/utilisateurs-mails.php	2019-08-28 19:17:46.745548530 +0200
@@ -0,0 +1,178 @@
+<?php
+// Sécurité
+define('OK',1);
+// Configuration
+include('config.php');
+// Fonctions
+include('fonctions.php');
+
+//////////////////
+// Autorisation //
+//////////////////
+
+// Accès aux professeurs connectés uniquement. Redirection pour les autres.
+if ( $autorisation < 5 )  {
+  header("Location: https://$domaine$chemin");
+  exit();
+}
+$mysqli = connectsql();
+// Si connexion light : on doit répéter son mot de passe pour aller plus loin
+// login.php contient fin()
+if ( $_SESSION['light'] )  {
+  $titre = 'Les courriels';
+  $actuel = 'utilisateurs-mails';
+  include('login.php');
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Préférence d'autorisation d'envoi de courriels 
+// Stockée dans la table prefs, nom = autorisation_mails
+//
+// $aut_envoi est une valeur numérique contenant l'ensembles des accès entre
+// les quatres groupes P (professeurs), L (lycée), C (colleurs) et E (élèves).
+// C'est la représentation décimale de la valeur binaire
+//    PP PL PC PE LP LL LC LE CP CL CC CE EP EL EC EE
+// où XY correspond à l'autorisation de X à envoyer un courriel à Y (1=oui).
+// Pour accéder aux autorisations du groupe numéro $n (2->E,3->C,4->L,5->P),
+// il faut décaler $autorisation de 4*$n bits et garder les 4 bits faibles, soit
+//    ( $aut_envoi >> 4*($n-2) ) & 15
+// Pour accéder à l'autorisation du groupe numéro $n vers le groupe numéro $m, 
+//    ( $aut_envoi >> 4*($n-2)+$m-2 ) & 1
+////////////////////////////////////////////////////////////////////////////////
+
+//////////////
+//// HTML ////
+//////////////
+debut($mysqli,'Modification des réglages de courriels',$message,5,'utilisateurs-mails');
+
+// Récupération des autorisations d'envoi
+$resultat = $mysqli->query('SELECT val FROM prefs WHERE nom = "autorisation_mails"');
+$aut_envoi = $resultat->fetch_row()[0];
+$autorisations = array(5=>'les professeurs',4=>'le lycée',3=>'les colleurs',2=>'les élèves');
+?>
+
+  <div id="icones">
+    <a class="icon-download" href="utilisateurs?xls" title="Télécharger la liste des utilisateurs en xls"></a>
+    <a class="icon-aide" title="Aide pour les modifications des courriels"></a>
+  </div>
+
+  <article>
+    <h3>Possibilités d'envoi de courriels</h3>
+    <table id="envoimails" class="utilisateurs">
+      <tbody>
+        <tr>
+          <th colspan="2"></th>
+          <th class="vertical"><span>Vers les professeurs</span></th>
+          <th class="vertical"><span>Vers le lycée</span></th>
+          <th class="vertical"><span>Vers les colleurs</span></th>
+          <th class="vertical"><span>Vers les éleves</span></th>
+        </tr>
+<?php
+foreach ( $autorisations as $a => $auto )  {
+  $envoi = ( $aut_envoi >> 4*($a-2) ) & 15;
+  echo <<<FIN
+        <tr data-id="$a">
+          <th>Par $auto</th><th class="icones"><span class="icon-ok" title="Établir l'autorisation d'envoi générale par ${autorisations[$a]}"></span>&nbsp;<span class="icon-nok" title="Supprimer l'autorisation d'envoi par ${autorisations[$a]}"></span></th>
+          
+FIN;
+  for ( $i=5; $i>=2; $i-- )  {
+    $ok = ( $envoi >> $i-2 ) & 1;
+    echo "<td class=\"icone\">$i|$ok</td>";
+  }
+  echo "        </tr>\n";
+}
+?>
+      </tbody>
+    </table>
+  </article>
+
+  <article>
+    <h3>Liste des utilisateurs</h3>
+    <table id="umails" class="utilisateurs">
+      <tbody>
+<?php
+// Tableau des utilisateurs (comptes validés uniquement)
+$autorisations = array(5=>'Professeur',4=>'Lycée',3=>'Colleur',2=>'Élève');
+foreach ( $autorisations as $a => $auto )  {
+  $resultat = $mysqli->query("SELECT id, nom, prenom, IF(LENGTH(mail),mail,\"Pas d'adresse\") AS mail, mailexp FROM utilisateurs WHERE mdp > '0' AND autorisation=$a ORDER BY nom, prenom, login");
+  $s = ( $a == 4 ) ? '' : 's';
+  if ( $n = $resultat->num_rows )  {
+    echo <<<FIN
+        <tr class="categorie"><th colspan="4">{$auto}$s ($n)</th></tr>
+        <tr><th>Identité</th><th>Nom affiché</th><th>Adresse électronique</th><th></th></tr>
+
+FIN;
+    while ( $r = $resultat->fetch_assoc() )
+      echo <<<FIN
+        <tr data-id="${r['id']}">
+          <td>${r['nom']} ${r['prenom']}</td>
+          <td>${r['mailexp']}</td>
+          <td>${r['mail']}</td>
+          <td class="icones"><a class="icon-edite" title="Éditer ce compte"></a></td>
+        </tr>
+
+FIN;
+    $resultat->free();
+  }
+}
+
+?>
+      </tbody>
+    </table>
+  </article>
+
+<?php
+
+// Aide et formulaire de modification
+?>
+
+  <div id="form-edite">
+    <a class="icon-ok" title="Valider ces modifications"></a>
+    <h3 class="edition">Modifier un utilisateur</h3>
+    <form>
+      <p id="compteactif">Vous pouvez ici modifier le compte XXX, de type YYY. Ce compte est actif. L'utilisateur du compte ne sera pas automatiquement prévenu de vos modifications.</p>
+      <p id="comptedesactive">Vous pouvez ici modifier le compte XXX, de type YYY. Ce compte a été désactivé&nbsp;: la connexion à ce Cahier de Prépa par ce compte n'est pas possible.</p>
+      <p id="demande">Vous pouvez ici modifier la demande XXX, de type YYY. Cette demande n'a pas encore été validée, vous pourrez la valider après modification.</p>
+      <p id="invitation">Vous pouvez ici modifier l'invitation XXX, de type YYY. L'utilisateur de ce compte ne sera pas automatiquement prévenu de vos modifications. Attention, la modification de l'identifiant ou de l'adresse électronique rendra impossible la validation de l'invitation par l'utilisateur concerné.</p>
+      <p>Seules les valeurs modifiées seront prises en compte. Pour modifier l'adresse électronique, il est nécessaire de la saisir deux fois.</p>
+      <p class="ligne"><label for="prenom">Prénom&nbsp;: </label><input type="text" name="prenom" value="" size="50"></p>
+      <p class="ligne"><label for="nom">Nom&nbsp;: </label><input type="text" name="nom" value="" size="50"></p>
+      <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" name="login" value="" size="50"></p>
+      <p class="ligne"><label for="mail1">Adresse électronique&nbsp;: </label><input type="email" name="mail1" value="" size="50"></p>
+      <p class="ligne"><label for="mail2">Confirmation (si modification)&nbsp;: </label><input type="email" name="mail2" value="" size="50"></p>
+      <p class="ligne"><label for="mailenvoi">Autorisation à l'envoi de courriel&nbsp;: </label><input type="checkbox" name="mailenvoi" value="1"></p>
+      <p class="ligne"><label for="mailexp">Nom affiché comme expéditateur/destinataire de courriel&nbsp;: </label><input type="text" name="mailexp" value="" size="50"></p>
+      <p class="ligne"><label for="mailcopie">Recevoir une copie des courriels envoyés&nbsp;: </label><input type="checkbox" name="mailcopie" value="1"></p>
+    </form>
+  </div>
+  
+  <div id="aide-page">
+    <h3>Aide et explications</h3>
+    <p>Il est possible ici de régler les possibilités d'envoi de courriels, de visualiser l'ensemble des adresses électronique et de modifier les données des utilisateurs pouvant se connecter à ce Cahier de Prépa.</p>
+    <p>Les associations entre les utilisateurs et les matières sont à régler à la <a href="utilisateurs-matieres">gestion utilisateurs-matières</a>.</p>
+    <p>L'ajout, la suppression et la désactivation des comptes utilisateurs est possibles à la <a href="utilisateurs">gestion des utilisateurs</a>.</p>
+    <p>Le seul bouton général <span class="icon-download"></span> permet de récupérer l'ensemble des noms et adresses électroniques de tous les utilisateurs en fichier de type <code>xls</code>, éditable par un logiciel tableur (Excel, LibreOffice Calc...).</p>
+    <h4>Possibilités d'envoi de courriels</h4>
+    <p>Le tableau est une double correspondance où chaque échange peut être autorisé (<span class="icon-ok"></span>) ou interdit (<span class="icon-nok"></span>). Un clic sur une de ces icônes commute entre autorisation et interdiction.</p>
+    <p>Les boutons <span class="icon-ok"></span> et <span class="icon-nok"></span> en début de ligne permettent de modifier d'un seul clic toutes les possibilités d'envoi de la ligne.</p>
+    <p>L'action est immédiate et s'applique instantanément à tous les utilisateurs, même connectés.</p>
+    <h4>Tableau récapitulatif</h4>
+    <p>Le tableau général présente tous les utilisateurs existants, ordonnés par type puis par ordre alphabétique.</p>
+    <p>Les données particulières des utilisateurs (nom, prénom, identifiant, adresse électronique, nom affiché comme expéditeur) sont modifiables en cliquant sur le bouton <span class="icon-edite"></span> qui ouvrira un formulaire.</p>
+    <p>Les identifiants sont modifiables ici. Ces identifiants ne servent qu'à la connexion&nbsp;: n'oubliez pas alors de prévenir l'utilisateur. Il pourra néanmoins se connecter à l'aide de son adresse électronique.</p>
+    <h4>Types d'utilisateurs</h4>
+    <p>Il existe cinq types d'utilisateurs&nbsp;:</p>
+    <ul>
+      <li>Les <em>professeurs</em> peuvent modifier tout ce qui est réglable dans ce Cahier de Prépa&nbsp;: pages d'informations et informations générales, utilisateurs, groupes d'élèves, matières, planning annuel. Tous les professeurs ont les mêmes droits sur ces catégories (il n'y a pas d'&laquo;&nbsp;administrateur&nbsp;&raquo;). Ils peuvent être associés ou non à une ou plusieurs matières, et pouvoir alors modifier ce qui concerne spécifiquement ces matières&nbsp;: programmes de colles, cahier de texte, documents, notes de colles. Ils peuvent voir l'ensemble des notes de colles mises dans les matières associées, et les récupérer sous forme de fichier xls. </li>
+      <li>Les utilisateurs liés à l'administration du <em>lycée</em> peuvent relever les notes de colles via une interface spécifique. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
+      <li>Les <em>colleurs</em> peuvent être associés ou non à une ou plusieurs matières (ils ne peuvent pas modifier leur liste des matières associées). Ils peuvent voir les contenus associés à ces matières et les contenus généraux, si l'accès de ces contenus est autorisé. Ils peuvent mettre des notes dans ces matières et voir leurs notes uniquement. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
+      <li>Les <em>élèves</em> peuvent être associés ou non à une ou plusieurs matières (ils ne peuvent pas modifier leur liste des matières associées). Ils peuvent voir les contenus associés à ces matières et les contenus généraux,  si l'accès de ces contenus est autorisé. Ils peuvent voir leurs notes de colles. Ils peuvent modifier leur identité et leur mot de passe. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
+      <li>Les <em>invités</em> sont des comptes prévus pour être éventuellement partagés entre plusieurs personnes. Une fois connecté, il est impossible de changer les paramètres du compte (identifiant, mot de passe, matières associées). Les invités peuvent voir les contenus associés à leurs matières et les contenus généraux, si l'accès de ces contenus est autorisé.</li>
+    </ul>
+    <p>Il n'est pas possible de changer le type d'un utilisateur (transformer un élève en colleur, etc.).</p>
+  </div>
+
+  <p id="log"></p>
+<?php
+fin(true);
+?>
diff -urN cahier-de-prepa8.1.1/utilisateurs-matieres.php cahier-de-prepa9.0.0/utilisateurs-matieres.php
--- cahier-de-prepa8.1.1/utilisateurs-matieres.php	2018-10-14 04:56:55.977792932 +0200
+++ cahier-de-prepa9.0.0/utilisateurs-matieres.php	2019-08-28 18:51:38.541712680 +0200
@@ -21,7 +21,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
@@ -45,7 +45,7 @@
 
   <article>
     <h3>Liste des utilisateurs</h3>
-    <table id="utilisateurs-matieres">
+    <table id="umats" class="utilisateurs">
       <thead>
         <tr>
           <th></th>
@@ -56,18 +56,18 @@
 $iconesmultiples = '';
 while ( $r = $resultat->fetch_assoc() )  {
   $matieres[$r['id']] = 0;
-  echo "          <th class=\"matieres\"><span id=\"m${r['id']}\">${r['nom']}</span></th>\n";
-  $iconesmultiples .= "\n          <th><span class=\"icon-ok\" data-id=\"${r['id']}\"></span></th>";
+  echo "          <th class=\"vertical\"><span id=\"m${r['id']}\">${r['nom']}</span></th>\n";
+  $iconesmultiples .= "\n          <th class=\"icone\"><span class=\"icon-ok\" data-id=\"${r['id']}\"></span></th>";
 }
 $resultat->free();
 echo "          <th></th>\n        </tr>\n      </thead>\n      <tbody>\n";
-$iconesmultiples .= "\n          <th><a class=\"icon-cocher\"></a></th>";
+$iconesmultiples .= "\n          <th class=\"icone\"><span class=\"icon-cocher\"></span></th>";
 
 // Nombre de colonnes du tableau
 $nc = count($matieres)+2;
 
 // Variables utilisées pour tout le tableau
-$autorisations = array(5=>'Professeur',4=>'Administratif',3=>'Colleur',2=>'Élève',1=>'Invité');
+$autorisations = array(5=>'Professeur',4=>'Lycée',3=>'Colleur',2=>'Élève',1=>'Invité');
 $requete = 'SELECT id, IF(LENGTH(nom),CONCAT(nom,\' \',prenom),CONCAT(\'<em>\',login,\'</em>\')) AS nomprenom, autorisation, SUBSTR(matieres,3) AS matieres FROM utilisateurs WHERE XXX ORDER BY autorisation DESC, nom, prenom, login';
 
 // Fonction de remplissage des lignes
@@ -78,8 +78,8 @@
   foreach ( explode(',',$r['matieres']) as $mid )
     $matieres[$mid] = 1;
   foreach ( $matieres as $mid => $ok )
-    echo "<td>$mid|$ok</td>";
-  echo "<td><input type=\"checkbox\"></td>\n        </tr>\n";
+    echo "<td class=\"icone\">$mid|$ok</td>";
+  echo "<td class=\"icone\"><input type=\"checkbox\"></td>\n        </tr>\n";
 }
 
 // Récupération des demandes à valider
@@ -103,8 +103,9 @@
 // Décompte total des utilisateurs (comptes validés et non désactivés) en fonction de leur type
 foreach ( $autorisations as $a => $auto)  {
   $resultat = $mysqli->query(str_replace('XXX',"mdp > '0' AND autorisation=$a",$requete));
+  $s = ( $a == 4 ) ? '' : 's';
   if ( $n = $resultat->num_rows )  {
-    echo "        <tr class=\"categorie\">\n          <th>{$auto}s ($n)</th>$iconesmultiples\n        </tr>\n";
+    echo "        <tr class=\"categorie\">\n          <th>{$auto}$s ($n)</th>$iconesmultiples\n        </tr>\n";
     while ( $r = $resultat->fetch_assoc() )
       ligne($r,$matieres);
     $resultat->free();
@@ -135,7 +136,8 @@
     <h3>Aide et explications</h3>
     <p>Il est possible ici de modifier les associations entre utilisateurs et matières.</p>
     <p>Chaque bouton <span class="icon-ok"></span> ou <span class="icon-nok"></span> à l'intersection d'un utilisateur et d'une matière permet de modifier immédiatement en cliquant l'association concernée.</p>
-    <p>Il est possible de traiter simultanément plusieurs utilisateurs en cochant les cases en bout de ligne et en cliquant sur les boutons d'action situés sur les lignes d'entêtes. Seuls des comptes de même types peuvent être traités simultanément. Les boutons <span class="icon-cocher"></span> permettent de cocher l'ensemble des comptes d'un type donné.</p>
+    <p>Attention, cette modification est immédiate&nbsp;: si vous supprimez une association, entre un élève et une matière, les notes qu'il pourrait avoir eues. Ajouter à nouveau cette association (en cliquant à nouveau dans la même case) ne permet pas de récupérer des notes perdues.</p>
+    <p>Il est possible de traiter simultanément plusieurs utilisateurs en cochant les cases en bout de ligne et en cliquant sur les boutons d'action qui apparaissent alors sur les lignes d'entêtes. Seuls des comptes de même types peuvent être traités simultanément. Les boutons <span class="icon-cocher"></span> permettent de cocher l'ensemble des comptes d'un type donné.</p>
   </div>
 
   <p id="log"></p>
diff -urN cahier-de-prepa8.1.1/utilisateurs.php cahier-de-prepa9.0.0/utilisateurs.php
--- cahier-de-prepa8.1.1/utilisateurs.php	2018-10-17 09:25:40.809667731 +0200
+++ cahier-de-prepa9.0.0/utilisateurs.php	2019-08-28 18:43:07.296546417 +0200
@@ -21,7 +21,7 @@
 
 // Accès aux professeurs connectés uniquement. Redirection pour les autres.
 if ( $autorisation < 5 )  {
-  header("Location: https://$site");
+  header("Location: https://$domaine$chemin");
   exit();
 }
 $mysqli = connectsql();
@@ -53,7 +53,7 @@
       return;
     }
     // Correspondance autorisation-type de compte
-    $categories = array(2=>'Élève',3=>'Colleur',4=>'Administration',5=>'Professeur');
+    $categories = array(2=>'Élève',3=>'Colleur',4=>'Lycée',5=>'Professeur');
     // Envoi des headers
     header("Content-Type: application/vnd.ms-excel");
     header("Content-Disposition: attachment; filename=utilisateurs.xls");
@@ -96,23 +96,63 @@
 
   <article>
     <h3>Liste des utilisateurs</h3>
-    <table id="utilisateurs">
+    <table id="u" class="utilisateurs">
       <tbody>
 <?php
 // Variables utilisées pour tout le tableau
-$autorisations = array(5=>'Professeur',4=>'Administratif',3=>'Colleur',2=>'Élève',1=>'Invité');
-$requete = 'SELECT id, nom, prenom, login, IF(LENGTH(mail),mail,"Pas d\'adresse") AS mail, autorisation, mailenvoi FROM utilisateurs WHERE XXX ORDER BY autorisation DESC, nom, prenom, login';
+$autorisations = array(5=>'Professeur',4=>'Lycée',3=>'Colleur',2=>'Élève',1=>'Invité');
+$requete = 'SELECT id, nom, prenom, login, autorisation FROM utilisateurs WHERE XXX ORDER BY autorisation DESC, nom, prenom, login';
+
+// Fonction d'affichage des lignes du tableau
+// $r : les données utilisateurs
+// $type : entier correspondant au type de compte : 1->demandes à valider,
+// 2->invitations non répondues, 3->comptes classiques, 4->comptes désactivés
+function ligne($r,$type)  {
+  $autorisations = $GLOBALS['autorisations'];
+  switch ($type)  {
+    case 1:
+      $login_autorisation = "<td>${r['login']}</td>\n          <td>${autorisations[$r['autorisation']]}</td>";
+      $deuxiemeicone = '<a class="icon-validutilisateur" title="Valider cette demande"></a>';
+      $texte = 'cette demande';
+      break;
+    case 2:
+      $login_autorisation = "<td>${r['login']}</td>\n          <td>${autorisations[$r['autorisation']]}</td>";
+      $deuxiemeicone = '<a class="icon-desactive" title="Désactiver cette invitation"></a>';
+      $texte = 'cette invitation';
+      break;
+    case 3:
+      $login_autorisation = "<td colspan=\"2\">${r['login']}</td>";
+      $deuxiemeicone = '<a class="icon-desactive" title="Désactiver ce compte"></a>';
+      $texte = 'ce compte';
+      break;
+    case 4:
+      $login_autorisation = "<td>${r['login']}</td>\n          <td>${autorisations[$r['autorisation']]}</td>";
+      $deuxiemeicone = '<a class="icon-active" title="Réactiver ce compte"></a>';
+      $texte = 'ce compte';
+  }
+  echo <<<FIN
+        <tr data-id="${r['id']}">
+          <td>${r['nom']}</td>
+          <td>${r['prenom']}</td>
+          $login_autorisation
+          <td class="icones">
+            <a class="icon-edite" title="Éditer $texte"></a>
+            $deuxiemeicone
+            <a class="icon-supprutilisateur" title="Supprimer $texte"></a>
+          </td>
+          <td class="icones"><input type="checkbox"></td>
+        </tr>
+
+FIN;
+}
 
 // Récupération des demandes à valider
 $resultat = $mysqli->query(str_replace('XXX','mdp LIKE \'*%\'',$requete));
 if ( $n = $resultat->num_rows )  {
   echo  <<<FIN
-        <tr class="categorie"><th colspan="7">Demandes en attente de validation ($n)</th></tr>
+        <tr class="categorie"><th colspan="6">Demandes en attente de validation ($n)</th></tr>
         <tr>
-          <th>Nom Prénom</th><th>Identifiant</th><th>Adresse électronique</th><th>Type</th>
-          <th class="icones">
-            <a class="icon-mail" title="Autoriser l'envoi de courriel pour les demandes cochées"></a>
-          </th>
+          <th>Nom</th><th>Prénom</th><th>Identifiant</th><th>Type</th>
           <th class="icones">
             <a class="icon-validutilisateur" title="Valider l'ensemble des demandes cochées"></a>
             <a class="icon-supprutilisateur" title="Supprimer l'ensemble des demandes cochées"></a>
@@ -122,22 +162,7 @@
 
 FIN;
   while ( $r = $resultat->fetch_assoc() )
-    echo <<<FIN
-        <tr data-id="${r['id']}">
-          <td>${r['nom']} ${r['prenom']}</td>
-          <td>${r['login']}</td>
-          <td>${r['mail']}</td>
-          <td>${autorisations[$r['autorisation']]}</td>
-          <td class="icones mailenvoi">${r['mailenvoi']}</td>
-          <td class="icones">
-            <a class="icon-edite" title="Éditer cette demande"></a>
-            <a class="icon-validutilisateur" title="Valider cette demande"></a>
-            <a class="icon-supprutilisateur" title="Supprimer cette demande"></a>
-          </td>
-          <td class="icones"><input type="checkbox"></td>
-        </tr>
-
-FIN;
+    ligne($r,1);
   $resultat->free();
 }
 
@@ -145,12 +170,9 @@
 $resultat = $mysqli->query(str_replace('XXX','mdp = \'?\'',$requete));
 if ( $n = $resultat->num_rows )  {
   echo <<<FIN
-        <tr class="categorie"><th colspan="7">Invitations envoyées en attente de réponse ($n)</th></tr>
+        <tr class="categorie"><th colspan="6">Invitations envoyées en attente de réponse ($n)</th></tr>
         <tr>
-          <th>Nom Prénom</th><th>Identifiant</th><th>Adresse électronique</th><th>Type</th>
-          <th class="icones">
-            <a class="icon-mail" title="Autoriser l'envoi de courriel pour les invitations cochées"></a>
-          </th>
+          <th>Nom</th><th>Prénom</th><th>Identifiant</th><th>Type</th>
           <th class="icones">
             <a class="icon-desactive" title="Désactiver tous les invitations cochées"></a>
             <a class="icon-supprutilisateur" title="Supprimer l'ensemble des invitations cochées"></a>
@@ -160,50 +182,19 @@
 
 FIN;
   while ( $r = $resultat->fetch_assoc() )
-    echo <<<FIN
-        <tr data-id="${r['id']}">
-          <td>${r['nom']} ${r['prenom']}</td>
-          <td>${r['login']}</td>
-          <td>${r['mail']}</td>
-          <td>${autorisations[$r['autorisation']]}</td>
-          <td class="icones mailenvoi">${r['mailenvoi']}</td>
-          <td class="icones">
-            <a class="icon-edite" title="Éditer cette invitation"></a>
-            <a class="icon-desactive" title="Désactiver cette invitation"></a>
-            <a class="icon-supprutilisateur" title="Supprimer cette invitation"></a>
-          </td>
-          <td class="icones"><input type="checkbox"></td>
-        </tr>
-
-FIN;
+    ligne($r,2);
   $resultat->free();
 }
 
 // Décompte total des utilisateurs (comptes validés et non désactivés) en fonction de leur type
 foreach ( $autorisations as $a => $auto)  {
   $resultat = $mysqli->query(str_replace('XXX',"mdp > '0' AND autorisation=$a",$requete));
+  $s = ( $a == 4 ) ? '' : 's';
   if ( $n = $resultat->num_rows )  {
-    if ( $a > 1 )
-      echo <<<FIN
-        <tr class="categorie"><th colspan="7">{$auto}s ($n)</th></tr>
-        <tr>
-          <th>Nom Prénom</th><th>Identifiant</th><th colspan="2">Adresse électronique</th>
-          <th class="icones">
-            <a class="icon-mail" title="Autoriser/supprimer l'envoi de courriel pour les comptes cochés"></a>
-          </th>
-          <th class="icones">
-            <a class="icon-desactive" title="Désactiver les comptes cochés"></a>
-            <a class="icon-supprutilisateur" title="Supprimer l'ensemble des comptes cochés"></a>
-          </th>
-          <th class="icones"><a class="icon-cocher" title="Tout cocher"></a></th>
-        </tr>
-
-FIN;
-    else
-      echo <<<FIN
-        <tr class="categorie"><th colspan="7">Invités ($n)</th></tr>
+    echo <<<FIN
+        <tr class="categorie"><th colspan="6">{$auto}$s ($n)</th></tr>
         <tr>
-          <th>Nom Prénom</th><th>Identifiant</th><th colspan="3">Adresse électronique</th>
+          <th>Nom</th><th>Prénom</th><th colspan="2">Identifiant</th>
           <th class="icones">
             <a class="icon-desactive" title="Désactiver les comptes cochés"></a>
             <a class="icon-supprutilisateur" title="Supprimer l'ensemble des comptes cochés"></a>
@@ -213,37 +204,7 @@
 
 FIN;
     while ( $r = $resultat->fetch_assoc() )
-      if ( $a > 1 )
-        echo <<<FIN
-        <tr data-id="${r['id']}">
-          <td>${r['nom']} ${r['prenom']}</td>
-          <td>${r['login']}</td>
-          <td colspan="2">${r['mail']}</td>
-          <td class="icones mailenvoi">${r['mailenvoi']}</td>
-          <td class="icones">
-            <a class="icon-edite" title="Éditer ce compte"></a>
-            <a class="icon-desactive" title="Désactiver ce compte"></a>
-            <a class="icon-supprutilisateur" title="Supprimer cet compte"></a>
-          </td>
-          <td class="icones"><input type="checkbox"></td>
-        </tr>
-
-FIN;
-      else
-        echo <<<FIN
-        <tr data-id="${r['id']}">
-          <td></td>
-          <td>${r['login']}</td>
-          <td colspan="3"></td>
-          <td class="icones">
-            <a class="icon-edite" title="Éditer ce compte"></a>
-            <a class="icon-desactive" title="Désactiver ce compte"></a>
-            <a class="icon-supprutilisateur" title="Supprimer cet compte"></a>
-          </td>
-          <td class="icones"><input type="checkbox"></td>
-        </tr>
-
-FIN;
+      ligne($r,3);
     $resultat->free();
   }
 }
@@ -252,12 +213,9 @@
 $resultat = $mysqli->query(str_replace('XXX','mdp LIKE \'!%\'',$requete));
 if ( $n = $resultat->num_rows )  {
   echo <<<FIN
-        <tr class="categorie"><th colspan="7">Comptes désactivés ($n)</th></tr>
+        <tr class="categorie"><th colspan="6">Comptes désactivés ($n)</th></tr>
         <tr>
-          <th>Nom Prénom</th><th>Identifiant</th><th>Adresse électronique</th><th>Type</th>
-          <th class="icones">
-            <a class="icon-mail" title="Autoriser l'envoi de courriel pour les comptes cochés"></a>
-          </th>
+          <th>Nom</th><th>Prénom</th><th>Identifiant</th><th>Type</th>
           <th class="icones">
             <a class="icon-active" title="Activer tous les comptes cochés"></a>
             <a class="icon-supprutilisateur" title="Supprimer toutes les comptes cochés"></a>
@@ -267,40 +225,7 @@
 
 FIN;
   while ( $r = $resultat->fetch_assoc() )
-    if ( $r['autorisation'] > 1 )
-      echo <<<FIN
-        <tr data-id="${r['id']}">
-          <td>${r['nom']} ${r['prenom']}</td>
-          <td>${r['login']}</td>
-          <td>${r['mail']}</td>
-          <td>${autorisations[$r['autorisation']]}</td>
-          <td class="icones mailenvoi">${r['mailenvoi']}</td>
-          <td class="icones">
-            <a class="icon-edite" title="Éditer ce compte"></a>
-            <a class="icon-active" title="Activer ce compte"></a>
-            <a class="icon-supprutilisateur" title="Supprimer cet compte"></a>
-          </td>
-          <td class="icones"><input type="checkbox"></td>
-        </tr>
-
-FIN;
-    else
-      echo <<<FIN
-        <tr data-id="${r['id']}">
-          <td></td>
-          <td>${r['login']}</td>
-          <td></td>
-          <td>${autorisations[$r['autorisation']]}</td>
-          <td></td>
-          <td class="icones">
-            <a class="icon-edite" title="Éditer ce compte"></a>
-            <a class="icon-active" title="Activer ce compte"></a>
-            <a class="icon-supprutilisateur" title="Supprimer ce compte"></a>
-          </td>
-          <td class="icones"><input type="checkbox"></td>
-        </tr>
-
-FIN;
+    ligne($r,4);
   $resultat->free();
 }
 ?>
@@ -332,7 +257,7 @@
         <option value="1">Invités</option>
         <option value="2">Élèves</option>
         <option value="3">Colleurs</option>
-        <option value="4">Administratifs</option>
+        <option value="4">Lycée</option>
         <option value="5">Professeurs</option>
       </select>
     </p>
@@ -357,17 +282,16 @@
     <p class="affichesimotdepasse">Sur chaque ligne, vous devez écrire nom, prénom et mot de passe (séparés par des virgules). Les utilisateurs ne seront pas prévenus automatiquement de cette création de compte, ce sera à vous de le faire. Ils pourront modifier leur mot de passe s'ils le souhaitent. Ils ne pourront envoyer des courriels que s'ils saisissent une adresse électronique.</p>
     <p class="affichesiinvite">Sur chaque ligne, vous devez écrire l'identifiant du compte et le mot de passe, séparés par une virgule. Vous pourrez ensuite communiquer ces coordonnées aux personnes concernées. Elles ne pourront pas modifier le mot de passe que vous avez choisi.</p>
     <textarea name="listeutilisateurs" rows="10" cols="100"></textarea>
-    <p class="ligne mailenvoi"><label for="mailenvoi">Autorisation à l'envoi de courriel&nbsp;: </label><input type="checkbox" name="mailenvoi" value="1"></p>
-    <p class="ligne mailliste"><label for="mailliste">Apparition dans la liste visible des élèves&nbsp;: </label><input type="checkbox" name="mailliste" value="1"></p>
   </form>
 
   <form id="form-prefs" data-action="prefsglobales">
     <h3 class="edition">Réglages de la gestion des comptes</h3>
     <p class="ligne"><label for="autoriser">Autoriser les demandes de création de comptes&nbsp;: </label>
-      <input type="checkbox" name="autoriser"<?php echo $creation_compte; ?>>
+      <input type="checkbox" id="autoriser" name="autoriser"<?php echo $creation_compte; ?>>
     </p>
     <input type="hidden" name="creation_compte" value="1">
     <p class="ligne">Pour modifier les associations entre utilisateurs et matières, il faut vous rendre sur la page de <a href="utilisateurs-matieres">gestion des associations utilisateurs-matières</a>.</p>
+    <p class="ligne">Pour voir les adresses électroniques et modifier les réglages d'envoi de courriels, il faut vous rendre sur la page de <a href="utilisateurs-mails">gestion des courriels</a>.</p>
   </form>
 
   <div id="form-edite">
@@ -384,10 +308,8 @@
       <p class="ligne"><label for="login">Identifiant&nbsp;: </label><input type="text" name="login" value="" size="50"></p>
       <p class="ligne"><label for="mail1">Adresse électronique&nbsp;: </label><input type="email" name="mail1" value="" size="50"></p>
       <p class="ligne"><label for="mail2">Confirmation (si modification)&nbsp;: </label><input type="email" name="mail2" value="" size="50"></p>
-      <p class="ligne"><label for="mailenvoi">Autorisation à l'envoi de courriel&nbsp;: </label><input type="checkbox" name="mailenvoi" value="1"></p>
-      <p class="ligne"><label for="mailexp">Nom d'expéditeur&nbsp;: </label><input type="text" name="mailexp" value="" size="50"></p>
+      <p class="ligne"><label for="mailexp">Nom affiché comme expéditateur/destinataire de courriel&nbsp;: </label><input type="text" name="mailexp" value="" size="50"></p>
       <p class="ligne"><label for="mailcopie">Recevoir une copie des courriels envoyés&nbsp;: </label><input type="checkbox" name="mailcopie" value="1"></p>
-      <p class="ligne"><label for="mailliste">Apparition dans la liste visible des élèves&nbsp;: </label><input type="checkbox" name="mailliste" value="1"></p>
     </form>
   </div>
   
@@ -395,6 +317,7 @@
     <h3>Aide et explications</h3>
     <p>Il est possible ici d'ajouter, de modifier et de supprimer des utilisateurs pouvant se connecter à ce Cahier de Prépa.</p>
     <p>Les associations entre les utilisateurs et les matières sont à régler à la <a href="utilisateurs-matieres">gestion utilisateurs-matières</a>.</p>
+    <p class="ligne">La modification des adresses électroniques est possible ici pour chaque utilisateur, mais il est préférable de vous rendre sur la page de <a href="utilisateurs-mails">gestion des courriels</a> si vous souhaitez les voir globalement. Vous pourrez aussi y modifier les réglages d'envoi de courriels.</p>
     <p>Les trois boutons généraux permettent de&nbsp;:</p>
     <ul>
       <li><span class="icon-ajoute"></span>&nbsp;: ouvrir un formulaire pour ajouter de nouveaux utilisateurs.</li>
@@ -403,19 +326,19 @@
     </ul>
     <h4>Tableau récapitulatif</h4>
     <p>Le tableau général présente tous les utilisateurs existants, ordonnés par type puis par ordre alphabétique.</p>
-    <p>Les données particulières des utilisateurs (nom, prénom, identifiant, adresse électronique) sont modifiables en cliquant sur le bouton <span class="icon-edite"></span> qui ouvrira un formulaire.</p>
-    <p>Les autres boutons du tableau permettent une action directe&nbsp;: autoriser ou non l'envoi de courriel, désactiver un compte, supprimer un compte, valider une demande.</p>
-    <p>Les identifiants sont modifiables ici&nbsp;: n'oubliez pas alors de prévenir l'utilisateur, qui ne pourra plus se connecter tant que vous ne lui aurez pas signifié son nouvel identifiant.</p>
+    <p>Les données particulières des utilisateurs (nom, prénom, identifiant, adresse électronique, nom affiché comme expéditeur) sont modifiables en cliquant sur le bouton <span class="icon-edite"></span> qui ouvrira un formulaire.</p>
+    <p>Les autres boutons du tableau permettent une action directe&nbsp;: désactiver un compte, supprimer un compte, valider une demande.</p>
+    <p>Les identifiants sont modifiables ici. Ces identifiants ne servent qu'à la connexion&nbsp;: n'oubliez pas alors de prévenir l'utilisateur. Il pourra néanmoins se connecter à l'aide de son adresse électronique.</p>
     <h4>Modifications multiples</h4>
-    <p>Il est possible de réaliser une modification identique sur un certain nombre de comptes en cochant les cases en bout de ligne et en cliquant sur les boutons d'action situés sur les lignes d'entêtes. Seuls des comptes de même types peuvent être traités simultanément. Les boutons <span class="icon-cocher"></span> permettent de cocher l'ensemble des comptes d'un type donné.</p>
+    <p>Il est possible de réaliser une modification identique sur un certain nombre de comptes en cochant les cases en bout de ligne et en cliquant sur les boutons d'action situés sur les lignes d'entêtes. Seuls des comptes de même type peuvent être traités simultanément. Les boutons <span class="icon-cocher"></span> permettent de cocher l'ensemble des comptes d'un type donné.</p>
     <h4>Suppression et désactivation</h4>
     <p>Chaque utilisateur peut être supprimé à l'aide du bouton <span class="icon-supprime"></span> (une confirmation sera demandée). Attention, lors de la suppression d'un utilisateur (élève, colleur, professeur), les colles le concernant sont automatiquement supprimées. Ne supprimez surtout pas un compte pour le recréer, modifiez-le directement.</p>
-    <p>La désactivation d'un compte permet de supprimer la possibilité de l'utilisateur de se connecter tout en conservant ses données comme son adresse électronique et les colles réalisées. C'est donc l'opération à réaliser pour un élève parti en cours d'année, dont on veut conserver les déclaration de colles jusqu'en fin d'année.</p>
+    <p>La désactivation d'un compte permet de supprimer la possibilité de l'utilisateur de se connecter tout en conservant ses données comme son adresse électronique et les colles réalisées. C'est donc l'opération à réaliser pour un élève parti en cours d'année, dont on veut conserver les notes de colles jusqu'en fin d'année.</p>
     <h4>Types d'utilisateurs</h4>
     <p>Il existe cinq types d'utilisateurs&nbsp;:</p>
     <ul>
       <li>Les <em>professeurs</em> peuvent modifier tout ce qui est réglable dans ce Cahier de Prépa&nbsp;: pages d'informations et informations générales, utilisateurs, groupes d'élèves, matières, planning annuel. Tous les professeurs ont les mêmes droits sur ces catégories (il n'y a pas d'&laquo;&nbsp;administrateur&nbsp;&raquo;). Ils peuvent être associés ou non à une ou plusieurs matières, et pouvoir alors modifier ce qui concerne spécifiquement ces matières&nbsp;: programmes de colles, cahier de texte, documents, notes de colles. Ils peuvent voir l'ensemble des notes de colles mises dans les matières associées, et les récupérer sous forme de fichier xls. </li>
-      <li>Les <em>administratifs</em> peuvent relever les notes de colles via une interface spécifique. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
+      <li>Les utilisateurs liés à l'administration du <em>lycée</em> peuvent relever les notes de colles via une interface spécifique. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
       <li>Les <em>colleurs</em> peuvent être associés ou non à une ou plusieurs matières (ils ne peuvent pas modifier leur liste des matières associées). Ils peuvent voir les contenus associés à ces matières et les contenus généraux, si l'accès de ces contenus est autorisé. Ils peuvent mettre des notes dans ces matières et voir leurs notes uniquement. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
       <li>Les <em>élèves</em> peuvent être associés ou non à une ou plusieurs matières (ils ne peuvent pas modifier leur liste des matières associées). Ils peuvent voir les contenus associés à ces matières et les contenus généraux,  si l'accès de ces contenus est autorisé. Ils peuvent voir leurs notes de colles. Ils peuvent modifier leur identité et leur mot de passe. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
       <li>Les <em>invités</em> sont des comptes prévus pour être éventuellement partagés entre plusieurs personnes. Une fois connecté, il est impossible de changer les paramètres du compte (identifiant, mot de passe, matières associées). Les invités peuvent voir les contenus associés à leurs matières et les contenus généraux, si l'accès de ces contenus est autorisé.</li>
@@ -443,7 +366,7 @@
     <p>Il existe cinq types d'utilisateurs&nbsp;:</p>
     <ul>
       <li>Les <em>professeurs</em> peuvent modifier tout ce qui est réglable dans ce Cahier de Prépa&nbsp;: pages d'informations et informations générales, utilisateurs, groupes d'élèves, matières, planning annuel. Tous les professeurs ont les mêmes droits sur ces catégories (il n'y a pas d'&laquo;&nbsp;administrateur&nbsp;&raquo;). Ils peuvent être associés ou non à une ou plusieurs matières, et pouvoir alors modifier ce qui concerne spécifiquement ces matières&nbsp;: programmes de colles, cahier de texte, documents, notes de colles. Ils peuvent voir l'ensemble des notes de colles mises dans les matières associées, et les récupérer sous forme de fichier xls. </li>
-      <li>Les <em>administratifs</em> peuvent relever les notes de colles via une interface spécifique. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
+      <li>Les utilisateurs liés à l'administration du <em>lycée</em> peuvent relever les notes de colles via une interface spécifique. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
       <li>Les <em>colleurs</em> peuvent être associés ou non à une ou plusieurs matières (ils ne peuvent pas modifier leur liste des matières associées). Ils peuvent voir les contenus associés à ces matières et les contenus généraux, si l'accès de ces contenus est autorisé. Ils peuvent mettre des notes dans ces matières et voir leurs notes uniquement. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
       <li>Les <em>élèves</em> peuvent être associés ou non à une ou plusieurs matières (ils ne peuvent pas modifier leur liste des matières associées). Ils peuvent voir les contenus associés à ces matières et les contenus généraux,  si l'accès de ces contenus est autorisé. Ils peuvent voir leurs notes de colles. Ils peuvent modifier leur identité et leur mot de passe. Ils peuvent envoyer des courriels si les professeurs le décident.</li>
       <li>Les <em>invités</em> sont des comptes prévus pour être éventuellement partagés entre plusieurs personnes. Une fois connecté, il est impossible de changer les paramètres du compte (identifiant, mot de passe, matières associées). Les invités peuvent voir les contenus associés à leurs matières et les contenus généraux, si l'accès de ces contenus est autorisé.</li>
