diff -urN cahier-de-prepa3.0.3/admin.php cahier-de-prepa3.1.0/admin.php
--- cahier-de-prepa3.0.3/admin.php	2013-08-20 01:24:03.686780490 +0200
+++ cahier-de-prepa3.1.0/admin.php	2013-10-22 16:52:51.324399507 +0200
@@ -176,7 +176,7 @@
 <?php echo $select_pages; ?>
       </select>
     </p>
-    <input class="ligne" type="text" name="titre" size=50 maxlength=65533 value="Titre">
+    <p class="transparent"><input class="ligne" type="text" name="titre" size=50 maxlength=65533 value="Titre"></p>
     <textarea name="texte" rows="6" cols="100"><p>Texte</p></textarea>
     <p class="ligne"><label for="cache">Ne pas diffuser sur la partie publique&nbsp;: </label><input type="checkbox" id="cache" name="cache" value="1"></p>
     <input type="hidden" name="id" value="0">
diff -urN cahier-de-prepa3.0.3/cdt.php cahier-de-prepa3.1.0/cdt.php
--- cahier-de-prepa3.0.3/cdt.php	2013-08-20 13:21:07.988157273 +0200
+++ cahier-de-prepa3.1.0/cdt.php	2013-10-23 21:25:23.119687577 +0200
@@ -70,36 +70,51 @@
   include('installation.php');
 }
 
-// Validation de n (numéro de semaine à voir)
-if ( isset($_REQUEST['n']) && is_numeric($n = $_REQUEST['n']) )  {
-  if ( !in_array($n,$sid) )
-    $n = 1;
+// Demande de visualisation de toute l'année
+if ( isset($_REQUEST['depuisledebut']) )  {
+  $n = 1;
+  $m = array_search($n,$sid);
+  $nb = count($sid);
 }
-// Sans argument, on souhaite afficher la semaine actuelle
-else {
- $date = ( isset($_REQUEST['date']) && preg_match('/\d{4}-\d{2}-\d{2}/',$_REQUEST['date']) ) ? '\''.trim($_REQUEST['date'],'\'').'\'' : 'NOW()';
-  $resultat = $mysqli->query("SELECT IF(vacances,(SELECT id FROM semaines WHERE debut > $date AND vacances = 0 LIMIT 1),id) AS id
-                              FROM semaines WHERE debut < $date ORDER BY debut DESC LIMIT 1");
-  if ( $resultat->num_rows )  {
-    $r = $resultat->fetch_assoc();
-    $n = $r['id'];
-    $resultat->free();
+else  {
+  // Validation de n (numéro de semaine à voir)
+  if ( isset($_REQUEST['n']) && is_numeric($n = $_REQUEST['n']) )  {
+    if ( !in_array($n,$sid) )
+      $n = 1;
   }
-  else
-    $n = 1;
-}
-$m = array_search($n,$sid);
+  // Sans argument, on souhaite afficher la semaine actuelle
+  else {
+    $date = ( isset($_REQUEST['date']) && preg_match('/\d{4}-\d{2}-\d{2}/',$_REQUEST['date']) ) ? '\''.trim($_REQUEST['date'],'\'').'\'' : 'NOW()';
+    $resultat = $mysqli->query("SELECT IF(vacances,(SELECT id FROM semaines WHERE debut > $date AND vacances = 0 LIMIT 1),id) AS id
+                                FROM semaines WHERE debut < $date ORDER BY debut DESC LIMIT 1");
+    if ( $resultat->num_rows )  {
+      $r = $resultat->fetch_assoc();
+      $n = $r['id'];
+      $resultat->free();
+    }
+    else
+      $n = 1;
+  }
+  $m = array_search($n,$sid);
 
-// Validation de nb (nombre de semaines à voir)
-if ( isset($_REQUEST['nb']) && is_numeric($nb = $_REQUEST['nb']) )  {
-  if ( $nb < 1 )
+  // Validation de nb (nombre de semaines à voir)
+  if ( isset($_REQUEST['nb']) && is_numeric($nb = $_REQUEST['nb']) )  {
+    if ( $nb < 1 )
+      $nb = 1;
+    if ( $nb > count($sid) - $m )
+      $nb = count($sid) - $m;
+  }
+  else
+    // Par défaut : affichage d'une seule semaine
     $nb = 1;
-  if ( $nb > count($sid) - $m )
-    $nb = count($sid) - $m;
 }
-else
-  // Par défaut : affichage d'une seule semaine
-  $nb = 1;
+
+// Récupération des types de séances
+$types = array();
+$resultat = $mysqli->query("SELECT id, cle, deb_fin_pour FROM `cdt-types` WHERE matiere = ${matiere['id']}");
+while ( $r = $resultat->fetch_assoc() )
+  $types[$r['id']] = $r;  
+$resultat->free();
 
 ///////////////////
 // Modifications //
@@ -126,12 +141,12 @@
   if ( isset($_REQUEST['modifie']) && strlen($_REQUEST['texte']) )  {
     
     // Validation du jour : à mettre dans la bonne semaine
-    $jour = preg_replace('/(\d{2})\/(\d{2})\/(\d{4})/','$3-$2-$1',$_REQUEST['jour']);
+    $jour = preg_filter('/(\d{2})\/(\d{2})\/(\d{4})/','$3-$2-$1',$_REQUEST['jour']);
     $resultat = $mysqli->query("SELECT id FROM semaines WHERE debut <= '$jour' ORDER BY debut DESC LIMIT 1");
     if ( $resultat->num_rows )  {
       $r = $resultat->fetch_assoc();
       $resultat->free();
-      // Correction évetuelle de n et nb pour que l'entrée soit visible après enregistrement
+      // Correction éventuelle de n et nb pour que l'entrée soit visible après enregistrement
       $s = array_search($r['id'],$sid);
       if ( ( $s < $m ) || ( $m+$nb <= $s ) )  {
         $n = $r['id'];
@@ -140,26 +155,35 @@
       }
       
       // Validation des autres données envoyées
-      $h_debut = preg_replace('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_debut']);
-      $h_fin = preg_replace('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_fin']);
-      $pour = preg_replace('/(\d{2})\/(\d{2})\/(\d{4})/','$3-$2-$1',$_REQUEST['pour']);
-      $tid = ( is_numeric($_REQUEST['tid']) ) ? $_REQUEST['tid'] : "(SELECT t.id FROM `cdt-types` AS t WHERE t.matiere=${matiere['id']} LIMIT 1)";
+      $tid = ( array_key_exists($_REQUEST['tid'],$types) ) ? $_REQUEST['tid'] : key($types);
+      $h_debut = $h_fin = '0:00';
+      $pour = '0000/00/00';
+      switch ( $types[$tid]['deb_fin_pour'] )  {
+        case 1:
+          $h_fin = preg_filter('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_fin']);
+        case 0:
+          $h_debut = preg_filter('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_debut']);
+          break;
+        case 2:
+          $pour = preg_filter('/(\d{2})\/(\d{2})\/(\d{4})/','$3-$2-$1',$_REQUEST['pour']);
+      }
       $texte = $mysqli->real_escape_string($_REQUEST['texte']);
       $demigroupe = ( isset($_REQUEST['demigroupe']) ) ? 1 : 0;
 
       // Si $id > 0 : modification d'une entrée existante. Si $id = 0, nouvelle entrée
+      // Ordre : d'abord ce qui n'a pas de fin, ensuite les séances "normales", ensuite les "pour le"
       if ( $id )
         $message = ( $mysqli->query("UPDATE cdt SET semaine = ${r['id']},
                                      jour = '$jour', h_debut = '$h_debut', h_fin = '$h_fin', pour = '$pour',
                                      type = $tid, texte = '$texte', demigroupe = $demigroupe WHERE id = $id")
-                  && $mysqli->query("ALTER TABLE cdt ORDER BY jour,matiere,h_debut,type")
+                  && $mysqli->query('ALTER TABLE cdt ORDER BY jour,matiere,pour,h_debut,h_fin,type')
         ) ? 'L\'entrée du cahier de texte a bien été modifiée.' : 'L\'entrée du cahier de texte n\'a pas pu être modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       else  {
         $cache = ( isset($_REQUEST['cache']) ) ? 1 : 0;
         $message = ( $mysqli->query("INSERT INTO cdt SET semaine = ${r['id']}, matiere = ${matiere['id']},
                                      jour = '$jour', h_debut = '$h_debut', h_fin = '$h_fin', pour = '$pour',
                                      type = $tid, texte = '$texte', demigroupe = $demigroupe, cache = $cache")
-                  && $mysqli->query("ALTER TABLE cdt ORDER BY jour,matiere,h_debut,type")
+                  && $mysqli->query('ALTER TABLE cdt ORDER BY jour,matiere,pour,h_debut,h_fin,type')
         ) ? 'L\'entrée du cahier de texte a bien été ajoutée.' : 'L\'entrée du cahier de texte n\'a pas pu être ajoutée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       }
     }
@@ -207,21 +231,18 @@
 
 // Formulaire de demande d'affichage
 $select_semaines = str_replace("\"$n\"","\"$n\" selected",$select_semaines);
-$types = $recherche_types = '';
-$resultat = $mysqli->query("SELECT cle FROM `cdt-types` WHERE matiere = ${matiere['id']}");
+$select_types = $recherche_types = '';
 if ( isset($_REQUEST['type']) )
-  while ( $r = $resultat->fetch_assoc() )  {
-    if ( $r['cle'] == $_REQUEST['type'] )  {
-      $types .= "\n        <option value=\"${r['cle']}\" selected>les ${r['cle']}</option>";
-      $recherche_types = " AND t.cle = '${r['cle']}'";
+  foreach ( $types as $type )
+    if ( $type['cle'] == $_REQUEST['type'] )  {
+      $select_types .= "\n        <option value=\"${type['cle']}\" selected>les ${type['cle']}</option>";
+      $recherche_types = " AND t.cle = '${type['cle']}'";
     }
     else
-      $types .= "\n        <option value=\"${r['cle']}\">les ${r['cle']}</option>"; 
-  }
+      $select_types .= "\n        <option value=\"${type['cle']}\">les ${type['cle']}</option>"; 
 else
-  while ( $r = $resultat->fetch_assoc() )
-    $types .= "\n        <option value=\"${r['cle']}\">les ${r['cle']}</option>";  
-$resultat->free();
+  foreach ( $types as $type )
+    $select_types .= "\n        <option value=\"${type['cle']}\">les ${type['cle']}</option>"; 
 
 $u = strlen($urladmin) ? "\n    <input type=\"hidden\" name=\"admin\" value=\"\">" : '';
 echo <<<FIN
@@ -231,9 +252,10 @@
     <input type="hidden" name="${matiere['cle']}" value="">
     <p>Afficher&nbsp;
       <select name="type">
-        <option value="tout">tout</option>$types
+        <option value="tout">tout</option>$select_types
       </select>
-      pendant&nbsp;<input type="text" name="nb" value="$nb" size="2">&nbsp;semaine(s) à partir du&nbsp;
+      <input type="submit" name="depuisledebut" id="depuisledebut" value="pour toute l'année">
+      ou&nbsp;pendant&nbsp;<input type="text" name="nb" value="$nb" size="2">&nbsp;semaine(s) à partir du&nbsp;
       <select name="n">$select_semaines
       </select>
       <input type="submit" name="" value="OK">
@@ -265,69 +287,61 @@
 <?php
 
   // Select des types d'entrée différent du précédent
-  $types = '';
-  $resultat = $mysqli->query("SELECT id, cle FROM `cdt-types` WHERE matiere = ${matiere['id']}");
-  while ( $r = $resultat->fetch_assoc() )
-    $types .= "\n        <option value=\"${r['id']}\">".ucfirst($r['cle']).'</option>';
-  $resultat->free();
+  $select_types = '';
+  foreach ( $types as $type )
+    $select_types .= "\n          <option value=\"${type['id']}\">".ucfirst($type['cle']).'</option>';
 }
 
 // Fonction d'affichage
 function affichage($r)  {
   $semaine = array('','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi');
-    // Formatage des horaires
-    if ( substr($r['pour'],0,2) == '00' )  {
-      $pour = '';
-      $heure = ( strlen($r['h_fin']) ) ? " de ${r['h_debut']} à ${r['h_fin']}" : " à ${r['h_debut']}";
-    }
-    else  {
-      $pour = " pour le ${r['pour']}";
-      $heure = '';
-    }
   // Affichage partie administrative
   if ( $GLOBALS['admin'] )  {
     if ( $id = $r['id'] )  {
-      $debut = "${semaine[$r['jour']]} ${r['date']}$heure&nbsp;: ${r['titre']}${r['demigroupe']}$pour";
+      $pour = ( strlen($r['heure']) ) ? '' : " pour le ${r['pour']}";
+      $debut = "${semaine[$r['jour']]} ${r['date']}${r['heure']}&nbsp;: ${r['titre']}$pour${r['demigroupe']}";
       $valide1 = '';
-      $valide = "\n      <input type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
-      $suppr = "\n      <input type=\"submit\" name=\"supprime\" value=\"Supprimer\" title=\"Supprimer l'entrée\">";
+      $valide = "\n        <input type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
+      $suppr = "\n        <input type=\"submit\" name=\"supprime\" value=\"Supprimer\" title=\"Supprimer l'entrée\">";
       $cache_nouveau = '';
       if ( $r['cache'] )  {
         $debut .= ' (entrée non diffusée sur la partie publique)';
         $cache_classe = ' cache';
-        $cache = "\n      <input type=\"submit\" name=\"montre\" value=\"Montrer\" title=\"Diffuser l'entrée, la rendre visible sur la partie publique\">";
+        $cache = "\n        <input type=\"submit\" name=\"montre\" value=\"Montrer\" title=\"Diffuser l'entrée, la rendre visible sur la partie publique\">";
       }
       else  {
         $cache_classe = '';
-        $cache = "\n      <input type=\"submit\" name=\"cache\" value=\"Cacher\" title=\"Ne plus diffuser l'entrée, la rendre invisible sur la partie publique\">";
+        $cache = "\n        <input type=\"submit\" name=\"cache\" value=\"Cacher\" title=\"Ne plus diffuser l'entrée, la rendre invisible sur la partie publique\">";
       }
     }
     else  {
       $debut = 'Nouvelle entrée du cahier';
       $valide1 = "\n    <input class=\"bouton\" type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
       $valide = $cache = $cache_classe = $suppr = '';
-      $cache_nouveau = "\n    <p class=\"ligne\"><label for=\"cache\">Ne pas diffuser sur la partie publique&nbsp;: </label><input type=\"checkbox\" id=\"cache\" name=\"cache\" value=\"1\"></p>";
+      $cache_nouveau = "\n      <p class=\"ligne\"><label for=\"cache\">Ne pas diffuser sur la partie publique&nbsp;: </label><input type=\"checkbox\" id=\"cache\" name=\"cache\" value=\"1\"></p>";
     }
     $demigroupe = ( strlen($r['demigroupe']) ) ? ' checked' : '';
-    $types = str_replace("\"${r['tid']}\"","\"${r['tid']}\" selected",$GLOBALS['types']);
+    $select_types = str_replace("\"${r['tid']}\"","\"${r['tid']}\" selected",$GLOBALS['select_types']);
     $type = ( isset($_REQUEST['type']) ) ? "&amp;type=${_REQUEST['type']}" : '';
     echo <<<FIN
   <div class="item cdt admin$cache_classe">
   <form action="${GLOBALS['p']}&amp;n=${GLOBALS['n']}&amp;nb=${GLOBALS['nb']}$type${GLOBALS['urladmin']}" method="post">$valide1
     <h3>$debut</h3>
-    <p class="boutons">$valide$cache$suppr
-    </p>
-    <p class="ligne"><label for="tid$id">Type&nbsp;:</label>
-      <select id="tid$id" name="tid">$types
-      </select>
-    </p>
-    <p class="ligne"><label for="jour$id">Jour&nbsp;: </label><input type="text" class="date" id="jour$id" name="jour" value="${r['date']}" size="8"></p>
-    <p class="ligne"><label for="h_debut$id">Heure de début&nbsp;: </label><input type="text" class="heure" id="h_debut$id" name="h_debut" value="${r['h_debut']}" size="5"></p>
-    <p class="ligne"><label for="h_fin$id">Heure de fin&nbsp;: </label><input type="text" class="heure" id="h_fin$id" name="h_fin" value="${r['h_fin']}" size="5"></p>
-    <p class="ligne"><label for="pour$id">Pour le&nbsp;: </label><input type="text" class="date" id="pour$id" name="pour" value="${r['pour']}" size="8"></p>
-    <p class="ligne"><label for="demigroupe$id">Séance en demi-groupe&nbsp;: </label><input type="checkbox" id="demigroupe$id" name="demigroupe" value="1"$demigroupe></p>
-    <textarea name="texte" rows="10" cols="100">${r['texte']}</textarea>$cache_nouveau
-    <input type="hidden" name="id" value="$id">
+    <div>
+      <p class="boutons">$valide$cache$suppr
+      </p>
+      <p class="ligne"><label for="tid$id">Type&nbsp;:</label>
+        <select id="tid$id" name="tid">$select_types
+        </select>
+      </p>
+      <p class="ligne"><label for="jour$id">Jour&nbsp;: </label><input type="text" class="date" id="jour$id" name="jour" value="${r['date']}" size="8"></p>
+      <p class="ligne"><label for="h_debut$id">Heure de début&nbsp;: </label><input type="text" class="heure" id="h_debut$id" name="h_debut" value="${r['h_debut']}" size="5"></p>
+      <p class="ligne"><label for="h_fin$id">Heure de fin&nbsp;: </label><input type="text" class="heure" id="h_fin$id" name="h_fin" value="${r['h_fin']}" size="5"></p>
+      <p class="ligne"><label for="pour$id">Pour le&nbsp;: </label><input type="text" class="date" id="pour$id" name="pour" value="${r['pour']}" size="8"></p>
+      <p class="ligne"><label for="demigroupe$id">Séance en demi-groupe&nbsp;: </label><input type="checkbox" id="demigroupe$id" name="demigroupe" value="1"$demigroupe></p>
+      <textarea name="texte" rows="10" cols="100">${r['texte']}</textarea>$cache_nouveau
+      <input type="hidden" name="id" value="$id">
+    </div>
   </form>
   </div>
 
@@ -338,7 +352,7 @@
     // Affichage partie publique
     echo <<<FIN
     <div class="item cdt">
-      <p class="titre">${semaine[$r['jour']]} ${r['date']}$heure&nbsp;: ${r['titre']}${r['demigroupe']}$pour</p>
+      <p class="titre">${semaine[$r['jour']]} ${r['date']}&nbsp;: ${r['titre']}${r['heure']}${r['demigroupe']}</p>
       <div>
   ${r['texte']}
       </div>
@@ -387,9 +401,15 @@
 echo $nav;
 
 // Récupération des entrées
-$resultat = $mysqli->query("SELECT cdt.id, cdt.texte, cdt.semaine, DATE_FORMAT(cdt.pour,'%d/%m/%Y') AS pour,
+$resultat = $mysqli->query("SELECT cdt.id, cdt.texte, cdt.semaine,
                             DATE_FORMAT(cdt.jour,'%w') AS jour, DATE_FORMAT(cdt.jour,'%d/%m/%Y') AS date,
-                            TIME_FORMAT(cdt.h_debut,'%kh%i') AS h_debut, IF(t.h_fin,TIME_FORMAT(cdt.h_fin,'%kh%i'),'') AS h_fin,
+                            CASE t.deb_fin_pour
+                              WHEN 0 THEN TIME_FORMAT(cdt.h_debut,' à %kh%i')
+                              WHEN 1 THEN CONCAT(TIME_FORMAT(cdt.h_debut,' de %kh%i'),TIME_FORMAT(cdt.h_fin,' à %kh%i'))
+                              ELSE '' END AS heure,
+                            TIME_FORMAT(cdt.h_debut,'%Hh%i') AS h_debut,
+                            TIME_FORMAT(cdt.h_fin,'%Hh%i') AS h_fin,
+                            DATE_FORMAT(cdt.pour,'%d/%m/%Y') AS pour,
                             IF(cdt.demigroupe,' (en demi-groupe)','') AS demigroupe, cdt.cache, t.id AS tid, t.titre
                             FROM cdt LEFT JOIN `cdt-types` AS t ON t.matiere = ${matiere['id']} AND t.id = cdt.type
                             WHERE cdt.semaine BETWEEN $n AND ${sid[$m+$nb-1]} AND cdt.matiere = ${matiere['id']} $recherche_types");
@@ -427,8 +447,10 @@
     echo "  <h2>Le cahier de texte ne contient pas de «&nbsp;${_REQUEST['type']}&nbsp;» pour les semaines choisies.</h2>\n\n";
 }
 
-// Récupération des boutons
+// Gestion des boutons de l'interface d'administration
 if ( $admin )  {
+
+  // Récupération des boutons
   $resultat = $mysqli->query("SELECT id, nom, jour, TIME_FORMAT(h_debut,'%Hh%i') AS h_debut, TIME_FORMAT(h_fin,'%Hh%i') AS h_fin,
                               type, demigroupe FROM `cdt-seances` WHERE matiere = ${matiere['id']}");
   $raccourcis = '';
@@ -437,35 +459,74 @@
     while ( $r = $resultat->fetch_assoc() )  {
       $raccourcis .= "<input type=\"button\" class=\"rac${r['id']}\" value=\"${r['nom']}\"> ";
       $r['demigroupe'] = ( $r['demigroupe'] ) ? 'true' : 'false';
-      $raccourcisjs .= "
-  \$('.rac${r['id']}').click(function() {
-    \$(this).parent().parent().find('[name=\"tid\"]').val('${r['type']}');
-    \$(this).parent().parent().find('[id^=\"h_debut\"]').val('${r['h_debut']}');
-    \$(this).parent().parent().find('[id^=\"h_fin\"]').val('${r['h_fin']}');
-    \$(this).parent().parent().find('[id^=\"demigroupe\"]').attr('checked', ${r['demigroupe']});
+      $raccourcisjs .= <<<FIN
+  $('.rac${r['id']}').click(function() {
+    $(this).parent().parent().find('[name="tid"]').val('${r['type']}').change();
+    $(this).parent().parent().find('[id^="h_debut"]').val('${r['h_debut']}');
+    $(this).parent().parent().find('[id^="h_fin"]').val('${r['h_fin']}');
+    $(this).parent().parent().find('[id^="demigroupe"]').attr('checked', ${r['demigroupe']});
     var today=new Date();
     var t=today.getDay();
     t = ${r['jour']}-t;
     if ( t>0 ) { t-=7; }
-    \$(this).parent().parent().find('[id^=\"jour\"]').datepick('setDate',t+'d');
-  });\n";
+    $(this).parent().parent().find('[id^="jour"]').datepick('setDate',t+'d');
+  });
+
+FIN;
     }
     $resultat->free();  
   }
-  echo <<<FIN
 
-  <script type="text/javascript" src="textarea.js.php?m=${matiere['id']}"></script>
-  
+  // Disparition automatique des heures et de la date d'échéance
+  echo <<<FIN
   <script type="text/javascript">
 $( function() {
+
+  // Modification du formulaire en fonction du type
+  $('[name="tid"]').change(function() {
+    var p1 = $(this).parent().parent().find('[id^="h_debut"]').parents('.ligne');
+    var p2 = $(this).parent().parent().find('[id^="h_fin"]').parents('.ligne');
+    var p3 = $(this).parent().parent().find('[id^="pour"]').parents('.ligne');
+    switch ( $(this).val() )  {
+FIN;
+  foreach ( $types as $id => $type )
+    switch ( $type['deb_fin_pour'] )  {
+      case 0:
+        echo "\n      case '$id': p1.show(); p2.hide(); p3.hide(); break;";
+        break;
+      case 1:
+        echo "\n      case '$id': p1.show(); p2.show(); p3.hide(); break;";
+        break;
+      case 2:
+        echo "\n      case '$id': p1.hide(); p2.hide(); p3.show(); break;";
+    }
+  echo <<<FIN
+
+    }
+  });
+  // Modification au chargement
+  $('[name="tid"]').change();
+
+  // Boutons de raccourcis
   $('<p class="boutons">$raccourcis</p>').clone().insertBefore($('.admin form').find('.ligne:first'));
 $raccourcisjs
   $('.date').datepick({dateFormat: 'dd/mm/yyyy', showTrigger: '<img src="js/calendar-blue.gif">'});
-  $('.heure').timeEntry({timeSteps: [1, 30, 0],separator: 'h'});
+  $('.heure').timeEntry({timeSteps: [1, 15, 0],separator: 'h'});
+
+  // URL plus lisible après clic du bouton "Toute l'année"
+  $('#depuisledebut').click(function() {
+    window.location.search = '?${matiere['cle']}&type='+$(this).prev('[name="type"]').val()+'&depuisledebut';
+    return false;
+  });
+
 });
   </script>
 
+  <script type="text/javascript" src="textarea.js.php?m=${matiere['id']}"></script>
+  
+
 FIN;
+
 }
 $mysqli->close();
 
diff -urN cahier-de-prepa3.0.3/cdt-seances.php cahier-de-prepa3.1.0/cdt-seances.php
--- cahier-de-prepa3.0.3/cdt-seances.php	2013-08-20 00:15:01.490647939 +0200
+++ cahier-de-prepa3.1.0/cdt-seances.php	2013-10-21 22:11:59.354247436 +0200
@@ -20,6 +20,13 @@
 if ( !isset($matiere) )
   exit('Mauvais paramètre d\'accès à cette page');
 
+// Récupération des types de séances
+$types = array();
+$resultat = $mysqli->query("SELECT id, cle, deb_fin_pour FROM `cdt-types` WHERE matiere = ${matiere['id']}");
+while ( $r = $resultat->fetch_assoc() )
+  $types[$r['id']] = $r;  
+$resultat->free();
+
 ///////////////////
 // Modifications //
 ///////////////////
@@ -28,6 +35,23 @@
   $mysqli->close();
   $mysqli = new mysqli($serveur,"$base-adm",$mdp,$base);
   $mysqli->set_charset('utf8');
+
+  // Vérification que l'identifiant est valide. Défaut : id=0 (nouveau raccourci)
+  if ( $id )  {
+    // Vérification de l'existence et récupération de l'ordre d'affichage
+    $resultat = $mysqli->query("SELECT ordre, nom, (SELECT max(ordre) FROM `cdt-seances` WHERE matiere = ${matiere['id']}) AS max
+                                FROM `cdt-seances` WHERE matiere = ${matiere['id']} AND id = $id");
+    if ( $resultat->num_rows )  {
+      $r = $resultat->fetch_assoc();
+      $ordre = $r['ordre'];
+      $resultat->free();
+    }
+    else
+      $id = 0;
+  }
+
+  // Sauvegarde de la table contenant les données
+  sauvegarde_mysql('cdt-seances');
   
   // Traitement d'un ajout/modification
   if ( isset($_REQUEST['modifie']) )  {
@@ -35,25 +59,28 @@
     if ( !strlen($_REQUEST['nom']) )
       $message = 'Il n\'est pas possible de valider un nom vide. Pour supprimer un raccourci, il faut cliquer sur Supprimer.';
     else  {
-      // Sauvegarde de la table contenant les données
-      sauvegarde_mysql('cdt-seances');
       // Validation des données envoyées
       $nom = $mysqli->real_escape_string($_REQUEST['nom']);
       $jour = ( is_numeric($_REQUEST['jour']) ) ? $_REQUEST['jour'] : 1;
-      $h_debut = preg_replace('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_debut']);
-      $h_fin = preg_replace('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_fin']);
-      $type = ( is_numeric($_REQUEST['tid']) ) ? $_REQUEST['tid'] : "(SELECT t.id FROM `cdt-types` AS t WHERE t.matiere=${matiere['id']} LIMIT 1)";
+      $tid = ( array_key_exists($_REQUEST['tid'],$types) ) ? $_REQUEST['tid'] : key($types);
+      $h_debut = $h_fin = '0:00';
+      switch ( $types[$tid]['deb_fin_pour'] )  {
+        case 1:
+          $h_fin = preg_filter('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_fin']);
+        case 0:
+          $h_debut = preg_filter('/(\d{1,2})h(\d{2})/','$1:$2',$_REQUEST['h_debut']);
+      }
       $demigroupe = ( isset($_REQUEST['demigroupe']) ) ? 1 : 0;
       // Si identifiant, modification d'un raccourci existant
       if ( $id )
         $message = ( $mysqli->query("UPDATE `cdt-seances` SET nom = '$nom', jour = $jour, h_debut = '$h_debut', h_fin = '$h_fin',
-                                     type = $type, demigroupe = $demigroupe WHERE id = $id")
+                                     type = $tid, demigroupe = $demigroupe WHERE id = $id")
         ) ? 'Le raccourci <em>'.stripslashes($nom).'</em> a bien été modifiée.' : 'Le raccourci <em>'.stripslashes($nom).'</em> n\'a pas pu être modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       // Sinon, nouveau raccourci
       else  {
         $message = ( $mysqli->query("INSERT INTO `cdt-seances` SET matiere = ${matiere['id']},
                                      ordre = (SELECT IFNULL(max(cs.ordre)+1,1) FROM `cdt-seances` AS cs WHERE cs.matiere = ${matiere['id']}),
-                                     nom = '$nom', jour = $jour, h_debut = '$h_debut', h_fin = '$h_fin', type = $type, demigroupe = $demigroupe")
+                                     nom = '$nom', jour = $jour, h_debut = '$h_debut', h_fin = '$h_fin', type = $tid, demigroupe = $demigroupe")
                   && $mysqli->query('ALTER TABLE `cdt-seances` ORDER BY ordre,matiere')
         ) ? 'Le raccourci <em>'.stripslashes($nom).'</em> a bien été ajouté.' : 'Le raccourci <em>'.stripslashes($nom).'</em> n\'a pas pu être ajouté. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       }
@@ -61,37 +88,25 @@
   }
 
   // Traitement d'une transformation/suppression
-  else  {
+  elseif ( $id )  {
     
-    // Vérification de l'existence et récupération de l'ordre d'affichage
-    $resultat = $mysqli->query("SELECT ordre, nom, (SELECT max(ordre) FROM `cdt-seances` WHERE matiere = ${matiere['id']}) AS max
-                                FROM `cdt-seances` WHERE id = $id");
-    if ( $resultat->num_rows )  {
-      $r = $resultat->fetch_assoc();
-      $ordre = $r['ordre'];
-      $resultat->free();
-
-      // Sauvegarde de la table contenant les données
-      sauvegarde_mysql('cdt-seances');
-
-      // Déplacement vers le haut
-      if ( isset($_REQUEST['monte']) && ( $ordre > 1 ) )
-        $message = ( $mysqli->query("UPDATE `cdt-seances` SET ordre = (2*$ordre-1-ordre) WHERE ( ordre = $ordre OR ordre = ($ordre-1) ) AND matiere = ${matiere['id']}")
-                  && $mysqli->query('ALTER TABLE `cdt-seances` ORDER BY ordre,matiere')
-        ) ? "Le raccourci <em>${r['nom']}</em> a bien été monté d'une place." : "Le raccourci <em>${r['nom']}</em> n'a pas pu être déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-
-      // Déplacement vers le bas
-      elseif ( isset($_REQUEST['descend']) && ( $ordre < $r['max'] ) )
-        $message = ( $mysqli->query("UPDATE `cdt-seances` SET ordre = (2*$ordre+1-ordre) WHERE ( ordre = $ordre OR ordre = ($ordre+1) ) AND matiere = ${matiere['id']}")
-                  && $mysqli->query('ALTER TABLE `cdt-seances` ORDER BY ordre,matiere')
-        ) ? "Le raccourci <em>${r['nom']}</em> a bien été descendu d'une place." : "Le raccourci <em>${r['nom']}</em> n'a pas pu être déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-
-      // Suppression
-      elseif ( isset($_REQUEST['supprime']) )
-        $message =  ( $mysqli->query("DELETE FROM `cdt-seances` WHERE id = $id")
-                   && $mysqli->query("UPDATE `cdt-seances` SET ordre = (ordre-1) WHERE ordre > $ordre AND matiere = ${matiere['id']}")
-        ) ? "Le raccourci <em>${r['nom']}</em> a bien été supprimé." : "Le raccourci <em>${r['nom']}</em> n'a pas pu être supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
-    }
+    // Déplacement vers le haut
+    if ( isset($_REQUEST['monte']) && ( $ordre > 1 ) )
+      $message = ( $mysqli->query("UPDATE `cdt-seances` SET ordre = (2*$ordre-1-ordre) WHERE ( ordre = $ordre OR ordre = ($ordre-1) ) AND matiere = ${matiere['id']}")
+                && $mysqli->query('ALTER TABLE `cdt-seances` ORDER BY ordre,matiere')
+      ) ? "Le raccourci <em>${r['nom']}</em> a bien été monté d'une place." : "Le raccourci <em>${r['nom']}</em> n'a pas pu être déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
+
+    // Déplacement vers le bas
+    elseif ( isset($_REQUEST['descend']) && ( $ordre < $r['max'] ) )
+      $message = ( $mysqli->query("UPDATE `cdt-seances` SET ordre = (2*$ordre+1-ordre) WHERE ( ordre = $ordre OR ordre = ($ordre+1) ) AND matiere = ${matiere['id']}")
+                && $mysqli->query('ALTER TABLE `cdt-seances` ORDER BY ordre,matiere')
+      ) ? "Le raccourci <em>${r['nom']}</em> a bien été descendu d'une place." : "Le raccourci <em>${r['nom']}</em> n'a pas pu être déplacé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
+
+    // Suppression
+    elseif ( isset($_REQUEST['supprime']) )
+      $message =  ( $mysqli->query("DELETE FROM `cdt-seances` WHERE id = $id")
+                 && $mysqli->query("UPDATE `cdt-seances` SET ordre = (ordre-1) WHERE ordre > $ordre AND matiere = ${matiere['id']}")
+      ) ? "Le raccourci <em>${r['nom']}</em> a bien été supprimé." : "Le raccourci <em>${r['nom']}</em> n'a pas pu être supprimé. Erreur MySQL n°".$mysqli->errno.', «'.$mysqli->error.'».';
   }
 
   // Passage en connexion MySQL en lecture seulement
@@ -134,50 +149,50 @@
         <option value="6">Samedi</option>
         <option value="0">Dimanche</option>
 ';
-$types = '';
-$resultat = $mysqli->query("SELECT id, cle FROM `cdt-types` WHERE matiere = ${matiere['id']}");
-while ( $r = $resultat->fetch_assoc() )
-  $types .= "\n        <option value=\"${r['id']}\">".ucfirst($r['cle']).'</option>';
-$resultat->free();
+$select_types = '';
+foreach ( $types as $type )
+  $select_types .= "\n          <option value=\"${type['id']}\">".ucfirst($type['cle']).'</option>';
 
 // Fonction d'affichage
 function affichage($r)  {
   if ( $id = $r['id'] )  {
     $debut = "Raccourci n°${r['ordre']}&nbsp;: ${r['nom']}";
     $valide1 = '';
-    $valide = "\n      <input type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
-    $monte = ( $r['ordre'] == 1 ) ? '' : "\n      <input type=\"submit\" name=\"monte\" value=\"&uarr;\" title=\"Remonter le raccourci dans l'ordre d'apparition\">";
-    $descend = ( $r['ordre'] == $GLOBALS['max'] ) ? '' : "\n      <input type=\"submit\" name=\"descend\" value=\"&darr;\" title=\"Descendre le raccourci dans l'ordre d'apparition\">";
-    $suppr = ( $GLOBALS['max'] == 1 ) ? '' : "\n      <input type=\"submit\" name=\"supprime\" value=\"Supprimer\" title=\"Supprimer le raccourci\">";
-    $types = str_replace("\"${r['type']}\"","\"${r['type']}\" selected",$GLOBALS['types']);
+    $valide = "\n        <input type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
+    $monte = ( $r['ordre'] == 1 ) ? '' : "\n        <input type=\"submit\" name=\"monte\" value=\"&uarr;\" title=\"Remonter le raccourci dans l'ordre d'apparition\">";
+    $descend = ( $r['ordre'] == $GLOBALS['max'] ) ? '' : "\n        <input type=\"submit\" name=\"descend\" value=\"&darr;\" title=\"Descendre le raccourci dans l'ordre d'apparition\">";
+    $suppr = ( $GLOBALS['max'] == 1 ) ? '' : "\n        <input type=\"submit\" name=\"supprime\" value=\"Supprimer\" title=\"Supprimer le raccourci\">";
+    $select_types = str_replace("\"${r['type']}\"","\"${r['type']}\" selected",$GLOBALS['select_types']);
     $semaine = str_replace("\"${r['jour']}\"","\"${r['jour']}\" selected",$GLOBALS['semaine']);
   }
   else  {
     $debut = 'Nouveau raccourci';
     $valide1 = "\n    <input class=\"bouton\" type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
     $valide = $monte = $descend = $suppr = '';
-    $types = $GLOBALS['types'];
+    $select_types = $GLOBALS['select_types'];
     $semaine = $GLOBALS['semaine'];
   }
   echo <<<FIN
   <div class="item admin">
   <form action="?${GLOBALS['mat']}${GLOBALS['urladmin']}" method="post">$valide1
     <h3>$debut</h3>
-    <p class="boutons">$valide$monte$descend$suppr
-    </p>
-    <p class="ligne"><label for="nom$id">Nom&nbsp;: </label><input type="input" id="nom$id" name="nom" value="${r['nom']}" size="50"></p>
-    <p class="ligne"><label for="tid$id">Type&nbsp;:</label>
-      <select id="tid$id" name="tid">$types
-      </select>
-    </p>
-    <p class="ligne"><label for="jour$id">Jour&nbsp;:</label>
-      <select id="jour$id" name="jour">$semaine
-      </select>
-    </p>
-    <p class="ligne"><label for="h_debut$id">Heure de début&nbsp;: </label><input type="text" class="heure" id="h_debut$id" name="h_debut" value="${r['h_debut']}" size="5"></p>
-    <p class="ligne"><label for="h_fin$id">Heure de fin&nbsp;: </label><input type="text" class="heure" id="h_fin$id" name="h_fin" value="${r['h_fin']}" size="5"></p>
-    <p class="ligne"><label for="demigroupe$id">Séance en demi-groupe&nbsp;: </label><input type="checkbox" id="demigroupe$id" name="demigroupe" value="1"${r['demigroupe']}></p>
-    <input type="hidden" name="id" value="$id">
+    <div>
+      <p class="boutons">$valide$monte$descend$suppr
+      </p>
+      <p class="ligne"><label for="nom$id">Nom&nbsp;: </label><input type="input" id="nom$id" name="nom" value="${r['nom']}" size="50"></p>
+      <p class="ligne"><label for="tid$id">Type&nbsp;:</label>
+        <select id="tid$id" name="tid">$select_types
+        </select>
+      </p>
+      <p class="ligne"><label for="jour$id">Jour&nbsp;:</label>
+        <select id="jour$id" name="jour">$semaine
+        </select>
+      </p>
+      <p class="ligne"><label for="h_debut$id">Heure de début&nbsp;: </label><input type="text" class="heure" id="h_debut$id" name="h_debut" value="${r['h_debut']}" size="5"></p>
+      <p class="ligne"><label for="h_fin$id">Heure de fin&nbsp;: </label><input type="text" class="heure" id="h_fin$id" name="h_fin" value="${r['h_fin']}" size="5"></p>
+      <p class="ligne"><label for="demigroupe$id">Séance en demi-groupe&nbsp;: </label><input type="checkbox" id="demigroupe$id" name="demigroupe" value="1"${r['demigroupe']}></p>
+      <input type="hidden" name="id" value="$id">
+    </div>
   </form>
   </div>
 
@@ -209,7 +224,33 @@
 
   <script type="text/javascript">
 $( function() {
-  $('.heure').timeEntry({timeSteps: [1, 30, 0],separator: 'h'});
+  
+  // Modification du formulaire en fonction du type
+  $('[name="tid"]').change(function() {
+    var p1 = $(this).parent().parent().find('[id^="h_debut"]').parents('.ligne');
+    var p2 = $(this).parent().parent().find('[id^="h_fin"]').parents('.ligne');
+    switch ( $(this).val() )  {
+FIN;
+  foreach ( $types as $id => $type )
+    switch ( $type['deb_fin_pour'] )  {
+      case 0:
+        echo "\n      case '$id': p1.show(); p2.hide(); break;";
+        break;
+      case 1:
+        echo "\n      case '$id': p1.show(); p2.show(); break;";
+        break;
+      case 2:
+        echo "\n      case '$id': p1.hide(); p2.hide(); break;";
+    }
+  echo <<<FIN
+
+    }
+  });
+  // Modification au chargement
+  $('[name="tid"]').change();
+
+  $('.heure').timeEntry({timeSteps: [1, 15, 0],separator: 'h'});
+  
 });
   </script>
 
diff -urN cahier-de-prepa3.0.3/cdt-types.php cahier-de-prepa3.1.0/cdt-types.php
--- cahier-de-prepa3.0.3/cdt-types.php	2013-08-20 00:14:05.806646157 +0200
+++ cahier-de-prepa3.1.0/cdt-types.php	2013-10-21 00:40:53.495768519 +0200
@@ -40,16 +40,16 @@
       // Validation des données envoyées
       $titre = $mysqli->real_escape_string($_REQUEST['titre']);
       $cle = $mysqli->real_escape_string($_REQUEST['cle']);
-      $h_fin = ( isset($_REQUEST['h_fin']) ) ? 1 : 0;
+      $deb_fin_pour = ( is_numeric($_REQUEST['deb_fin_pour']) ) ? $_REQUEST['deb_fin_pour'] : 1;
       // Si identifiant, modification d'un type existant
       if ( $id )
-        $message = ( $mysqli->query("UPDATE `cdt-types` SET titre = '$titre', cle = '$cle', h_fin = $h_fin WHERE id = $id")
+        $message = ( $mysqli->query("UPDATE `cdt-types` SET titre = '$titre', cle = '$cle', deb_fin_pour = $deb_fin_pour WHERE id = $id")
         ) ? 'Le type <em>'.stripslashes($titre).'</em> a bien été modifiée.' : 'Le type <em>'.stripslashes($titre).'</em> n\'a pas pu être modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       // Sinon, nouveau type
       else  {
         $message = ( $mysqli->query("INSERT INTO `cdt-types` SET matiere = ${matiere['id']},
                                      ordre = (SELECT max(ct.ordre)+1 FROM `cdt-types` AS ct WHERE ct.matiere = ${matiere['id']}),
-                                     titre = '$titre', cle = '$cle', h_fin = $h_fin")
+                                     titre = '$titre', cle = '$cle', deb_fin_pour = $deb_fin_pour")
                   && $mysqli->query('ALTER TABLE `cdt-types` ORDER BY ordre,matiere')
         ) ? 'Le type <em>'.stripslashes($titre).'</em> a bien été ajouté.' : 'Le type <em>'.stripslashes($titre).'</em> n\'a pas pu être ajouté. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       }
@@ -131,6 +131,11 @@
 <?php
 
 // Fonction d'affichage
+$deb_fin_pour = '
+        <option value="0">Début seulement</option>
+        <option value="1">Début et fin</option>
+        <option value="2">Pas d\'horaire mais date d\'échéance</option>
+';
 function affichage($r)  {
   if ( $id = $r['id'] )  {
     $debut = "Type n°${r['ordre']}&nbsp;: ${r['titre']}";
@@ -141,11 +146,13 @@
     $monte = ( $r['ordre'] == 1 ) ? '' : "\n      <input type=\"submit\" name=\"monte\" value=\"&uarr;\" title=\"Remonter le type dans l'ordre d'apparition\">";
     $descend = ( $r['ordre'] == $GLOBALS['max'] ) ? '' : "\n      <input type=\"submit\" name=\"descend\" value=\"&darr;\" title=\"Descendre le type dans l'ordre d'apparition\">";
     $suppr = ( ( $GLOBALS['max'] == 1 ) || ( $r['n'] ) ) ? '' : "\n      <input type=\"submit\" name=\"supprime\" value=\"Supprimer\" title=\"Supprimer le type\">";
+    $deb_fin_pour = str_replace("\"${r['deb_fin_pour']}\"","\"${r['deb_fin_pour']}\" selected",$GLOBALS['deb_fin_pour']);
   }
   else  {
     $debut = 'Nouveau type';
     $valide1 = "\n    <input class=\"bouton\" type=\"submit\" name=\"modifie\" value=\"Valider\" title=\"Valider les modifications\">";
     $valide = $monte = $descend = $suppr = '';
+    $deb_fin_pour = $GLOBALS['deb_fin_pour'];
   }
   echo <<<FIN
   <div class="item admin">
@@ -155,7 +162,10 @@
     </p>
     <p class="ligne"><label for="titre$id">Titre (singulier)&nbsp;: </label><input type="input" id="titre$id" name="titre" value="${r['titre']}" size="50"></p>
     <p class="ligne"><label for="cle$id">Clé (pluriel)&nbsp;: </label><input type="input" id="cle$id" name="cle" value="${r['cle']}" size="50"></p>
-    <p class="ligne"><label for="h_fin$id">Affiche une heure de fin&nbsp;: </label><input type="checkbox" id="h_fin$id" name="h_fin" value="1"${r['h_fin']}></p>
+    <p class="ligne"><label for="deb_fin_pour$id">Affichage d'horaires&nbsp;:</label>
+      <select id="deb_fin_pour$id" name="deb_fin_pour">$deb_fin_pour
+      </select>
+    </p>
     <input type="hidden" name="id" value="$id">
   </form>
   </div>
@@ -167,14 +177,14 @@
 
 // Formulaire vide pour un nouveau type
 $mat = $matiere['cle'];
-affichage(array('id' => 0, 'titre' => '', 'cle' => '', 'h_fin' => ''));
+affichage(array('id' => 0, 'titre' => '', 'cle' => '', 'deb_fin_pour' => 1));
 
 // Affichage des types
 $resultat = $mysqli->query("SELECT MAX(ordre) FROM `cdt-types` WHERE matiere = ${matiere['id']}");
 $r = $resultat->fetch_row();
 $max = $r[0];
 $resultat->free();
-$resultat = $mysqli->query("SELECT ct.id, ct.ordre, ct.titre, ct.cle, IF(ct.h_fin=1,' checked','') AS h_fin, COUNT(cdt.id) AS n
+$resultat = $mysqli->query("SELECT ct.id, ct.ordre, ct.titre, ct.cle, ct.deb_fin_pour, COUNT(cdt.id) AS n
                             FROM `cdt-types` AS ct LEFT JOIN cdt ON cdt.type = ct.id 
                             WHERE ct.matiere = ${matiere['id']} GROUP BY ct.ordre");
 $mysqli->close();
diff -urN cahier-de-prepa3.0.3/CHANGELOG.php cahier-de-prepa3.1.0/CHANGELOG.php
--- cahier-de-prepa3.0.3/CHANGELOG.php	2013-09-03 22:02:38.851865934 +0200
+++ cahier-de-prepa3.1.0/CHANGELOG.php	2013-10-24 16:13:04.153852739 +0200
@@ -1,4 +1,4 @@
-Version actuelle : 3.0.3 (03/09/13)
+Version actuelle : 3.1.0 (24/10/13)
 ===================
 Changements :
 1.0   31/08/11 Première version
@@ -77,23 +77,39 @@
         Suppression du exit de CHANGELOG.php
 3.0.3 03/09/13 Correction d'un bug dans docs.php modifiant les dates d'envoi et tailles de tous
         les documents lors de la mise à jour d'un seul (merci PH. Jondot)
+3.1.0 24/10/13 Nouvelles foncionnalités :
+        * Modifications des cahiers de texte (possibilité de voir toute l'année, affiche/efface
+        les horaires en fonction du type de séance dans l'interface administrative)
+        * Possibilité de prévisualiser les textes tapés en textarea
+        * Icones dans les informations récentes, meilleure présentation des informations récentes,
+        liens pour les documents dans le flux RSS
+        Corrections de bugs :
+        * Textarea pour les informations (admin.php et index.php) qui ne s'affiche pas au dépliage
+        sous certaines versions de Safari/Safari Mobile (merci F. Evrard)
+        * Rechargement anormal de la page courante après reconnexion via javascript (timeout.js)
+        * Affichage des documents dans l'ordre "naturel" (merci PJ. Desnoux)
+        * Affichage de l'icone pour les documents à extension en majuscule
+        * Liens incorrects dans le flux RSS
 
 ===================
 
-[ 3.1 ] Décembre 2013
- * vraie version mobile
- * modifications du flux RSS : liens dans les textes ; "Doc :" pour les documents
-
-[ 3.2 ] Février 2014
- * gestion des informations récentes : choix des notifications, suppressions/modifications
+[ 3.2 ] Décembre 2013
+ * page de lecture du flux RSS : affichage complet + lien
+ * ordre d'affichage des documents/cahiers de textes : chronologique, chronologique inversé
  * choix possible des répertoires apparaissant dans le menu
  * pages d'informations associées à des matières
 
-[ 3.3 ] Avril 2014
- * suppression multiple d'informations
+[ 3.3 ] Février 2014
+ * gestion des informations récentes : choix des notifications, suppressions/modifications
+ * gestion *des* flux RSS : plusieurs flux avec choix possible de ce qui y apparait
+ * gestion personnelle du time-out
+
+[ 3.4 ] Avril 2014
+ * suppression multiple d'informations, d'informations récentes
  * exportation des données
  
 [ 4.0 ] Août 2014
+ * vraie version mobile
  * vérification des saisies de texte et aide au formatage en HTML, ajout automatique
  de balises <p>, suppression des fin de lignes et lignes vides finales
  * choix du regroupement dans le cahier de texte, par séance, par jour, par semaine
@@ -104,4 +120,8 @@
  * paramétrage des styles pour les titres, des couleurs
  * copié/collé depuis Word ?
  * agenda ?
-
+ * tags dans les cahiers de texte
+ * nouvelles matières : interdiction de garder la clé par défaut/d'avoir une clé déjà existante
+ * Bug : si semaines mises à jour, il faut modifier les cahiers de texte et les programmes de colles
+dans la mesure du possible.
+ * Bug : le déplacement d'un répertoire ne modifie pas les informations récentes ni le flux RSS
diff -urN cahier-de-prepa3.0.3/colles.php cahier-de-prepa3.1.0/colles.php
--- cahier-de-prepa3.0.3/colles.php	2013-08-23 10:27:58.252119232 +0200
+++ cahier-de-prepa3.1.0/colles.php	2013-10-24 12:01:32.821369814 +0200
@@ -51,7 +51,7 @@
     sauvegarde_mysql('colles');
 
     // Pour les informations récentes
-    $titre_recent = "Colles du ${r['debut']} en ".addslashes($matiere['nom']);
+    $titre_recent = "<img class=\"icone\" src=\"icones/colle.png\"> Colles du ${r['debut']} en ".addslashes($matiere['nom']);
     $lien_recent = 'colles?'.addslashes($matiere['cle'])."&amp;n=$id";
 
     // Ajout d'un nouveau programme de colles. Il ne faut pas pouvoir insérer un programme vide par erreur
diff -urN cahier-de-prepa3.0.3/css/couleurs.css cahier-de-prepa3.1.0/css/couleurs.css
--- cahier-de-prepa3.0.3/css/couleurs.css	2013-08-18 10:19:13.238278378 +0200
+++ cahier-de-prepa3.1.0/css/couleurs.css	2013-10-22 12:11:26.247859183 +0200
@@ -25,3 +25,6 @@
 table { border: medium solid #999; }
 table td, table th { border: thin solid #555; }
 #etape { list-style-type: circle; font-weight: 900; }
+#preview { background-color: #EEFFDD; }
+#preview > h2 { color: #444; background-color: #C4D2B6;  border-bottom: 1px solid black;}
+#preview > p { color: #444; background-color: #C4D2B6;  border-top: 1px solid black;}
diff -urN cahier-de-prepa3.0.3/css/print.css cahier-de-prepa3.1.0/css/print.css
--- cahier-de-prepa3.0.3/css/print.css	2012-12-06 00:03:07.000000000 +0100
+++ cahier-de-prepa3.1.0/css/print.css	2013-09-26 17:17:20.426908787 +0200
@@ -4,7 +4,7 @@
 #contenu { width: 100%; font-size: 10pt; }
 
 /* Pas d'affichage pour certains éléments */
-#menu, .prec, .suiv, #bas, #deconnexion, form { display: none; }
+#menu, #recent, .prec, .suiv, #bas, #deconnexion, form { display: none; }
 a { color: black; text-decoration: none; }
 
 /* Positionnements principaux */
diff -urN cahier-de-prepa3.0.3/css/style.css cahier-de-prepa3.1.0/css/style.css
--- cahier-de-prepa3.0.3/css/style.css	2013-08-21 16:32:53.931290275 +0200
+++ cahier-de-prepa3.1.0/css/style.css	2013-10-24 17:19:01.685979380 +0200
@@ -15,6 +15,7 @@
 ul { margin: 0.5em 2%; padding: 0 4% 0 6%; }
 p { margin: 0.5em 2%; padding: 0 4%; }
 div, form { margin: 0; padding: 0; }
+img { border: none; }
 #colonne { width: 280px; float: left; margin: -1em 30px 3em; }
 #menu, #recent { padding: 1em 20px; }
 #recent { margin-top: 2em; }
@@ -47,13 +48,16 @@
 #menu div+div { margin-top: 0.3em; padding-top: 0.5em; }
 #menu h3, #recent h3 { text-align: center; margin: 0 5% 0.5em; padding: 0.2em 5px; }
 #menu h4 { text-align: center; margin: 0; }
-#menu a, #recent a { display: block; margin-bottom: 0.2em; padding: 0; }
+#menu a { display: block; margin-bottom: 0.2em; padding: 0; }
 #menu a.ligne { display: inline !important; }
 #menu p.menusupp { margin: 0 3% 0.3em; font-size: 0.9em; }
 #menu p { padding: 0.1em 0px; }
 #actuel { font-style: italic; }
 #rss { display: inline !important; margin: 0 !important; vertical-align: top; }
-#rss img { height: 1.1em; }
+#rss .icone { float: right; }
+#recent .icone { height: 1.2em; vertical-align: bottom; margin-right: 0.2em; }
+#recent a { display: block; margin-bottom: 0.4em; padding: 0;
+  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
 
 /* Alignements des formulaires */
 input, select, textarea, #bas {
@@ -94,6 +98,7 @@
 input.ligne, textarea { width: 92%; margin: 0.5em 4% 0.2em; }
 p.ligne label { font-weight: 700; vertical-align: sub; }
 p.ligne input, p.ligne select, p.ligne code { width: 60%; float: right; }
+p.ligne input[type="checkbox"] { width: 1em;}
 p.ligne code { padding-top: 0.4em; }
 p.ligne + textarea { margin-top: 0; }
 table#semaines, table#utilisateurs { width: 80%; margin: 1em 10%; border-collapse: collapse; }
@@ -103,3 +108,12 @@
 .timeEntry_control { float: right; margin: 3px 5px 0 0; }
 .datepick-trigger { float: right; margin: 5px 7px 0 0; }
 #message { position: fixed; left: 25%; z-index: 1; background-color: #FFBBBB; }
+#preview_fond { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: #000; opacity: 0.2; filter: alpha(opacity=20); z-index: 1000; }
+#preview { position: absolute; top: 25%; left: 25%; width: 50%; z-index: 1001; padding: 0; margin: 0; overflow: auto; }
+#preview > h2 { margin: 0; padding: 0.5em 0; text-align: center; }
+#preview > div { margin: 1em 2% 4em; }
+#preview > p { font-size: 0.8em; text-align: center; width: 100%; position: absolute; left: 0; bottom: 0; margin: -3em 0 0; padding: 1em 0; }
+/* Pour certaines versions de webkit : pas de input seul, sinon le dépliage fonctionne partiellement */
+p.transparent { margin: 0; padding: 0; }
+
+
diff -urN cahier-de-prepa3.0.3/debut.php cahier-de-prepa3.1.0/debut.php
--- cahier-de-prepa3.0.3/debut.php	2013-08-20 10:16:39.923803093 +0200
+++ cahier-de-prepa3.1.0/debut.php	2013-10-24 15:20:31.149751842 +0200
@@ -169,12 +169,14 @@
     $resultat = $mysqli->query('SELECT UNIX_TIMESTAMP(heure) AS heure, titre, lien, texte FROM recents');
     while ( $r = $resultat->fetch_assoc() )  {
       $d = date(DATE_RSS,$r['heure']);
+      $titre = preg_replace('/^<[^>]*> /','',$r['titre']);
+      $texte = preg_replace('/href="([^h])/',"href=\"http://${GLOBALS['site']}/\\1",$r['texte']);
       $rss .= <<<FIN
     <item>
-      <title><![CDATA[${r['titre']}]]></title>
+      <title><![CDATA[$titre]]></title>
       <link>http://${GLOBALS['site']}/${r['lien']}</link>
       <guid isPermaLink="false">${r['heure']}</guid>
-      <description><![CDATA[${r['texte']}]]></description>
+      <description><![CDATA[$texte]]></description>
       <pubDate>$d</pubDate>
     </item>
 
diff -urN cahier-de-prepa3.0.3/docs.php cahier-de-prepa3.1.0/docs.php
--- cahier-de-prepa3.0.3/docs.php	2013-09-03 18:48:32.147493238 +0200
+++ cahier-de-prepa3.1.0/docs.php	2013-10-24 14:35:18.165665026 +0200
@@ -34,6 +34,23 @@
     $rid = 1;
 }
 
+/////////////////////////////////////
+// Liste des icones pour affichage //
+/////////////////////////////////////
+$icones = array(
+  '.pdf' => 'pdf', '.ps' => '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',
+  '.py' => 'python',
+  '.avi' => 'avi', '.mpeg' => 'avi', '.mpg' => 'avi', '.wmv' => 'avi', '.mp4' => 'avi', '.ogv' => 'avi', '.qt' => 'avi', '.mov' => 'avi', '.mkv' => 'avi', 'flv' => 'avi',
+  '.mp3' => 'mp3', '.ogg' => 'mp3', '.oga' => 'mp3', '.wma' => 'mp3', '.wav' => 'mp3', '.ra' => 'mp3', '.rm' => 'mp3',
+  '.txt' => 'txt', '.rtf' => 'txt',
+  '.zip' => 'exe', '.rar' => 'exe', '.7z' => 'zip',
+  '.exe' => 'exe', '.sh' => 'exe', '.ml' => 'exe', '.mw' => 'exe', '' => 'exe'
+);
+
 //////////////////////////////////
 // Modifications de répertoires //
 //////////////////////////////////
@@ -154,6 +171,27 @@
   sauvegarde_mysql('reps');
   sauvegarde_mysql('docs');
 
+  // Fonction MySQL pour l'ordre "naturel" (1,2,10,11 et non 1,10,11,2)
+  $mysqli->query('DROP FUNCTION IF EXISTS ZPAD');
+  $mysqli->query('CREATE FUNCTION ZPAD(s VARCHAR(100))
+  RETURNS VARCHAR(100)
+BEGIN
+  DECLARE i INT DEFAULT 1;
+  DECLARE n INT DEFAULT 1;
+  WHILE i <= LENGTH(s) DO
+    IF FIND_IN_SET(SUBSTRING(s,i,1),"0,1,2,3,4,5,6,7,8,9") THEN
+      SET n = i + 1;
+      WHILE FIND_IN_SET(SUBSTRING(s,n,1),"0,1,2,3,4,5,6,7,8,9") DO
+        SET n = n + 1;
+      END WHILE;
+      SET s = CONCAT(LEFT(s,i-1),REPEAT("0",10-n+i),RIGHT(s,CHAR_LENGTH(s)+1-i));
+      SET i = i + 10;
+    END IF;
+    SET i = i + 1;
+  END WHILE;
+  RETURN s;
+END');
+
   // Traitement d'une modification d'un document
   if ( isset($_REQUEST['modifie_doc']) && ( $id ) )  {
     if ( !strlen($_REQUEST['nom']) )
@@ -166,9 +204,9 @@
       $nom = basename(str_replace($doc['ext'],'',$_REQUEST['nom']));
       if ( $nom != $doc['nom'] )  {
         // real_escape_string seulement pour la requête SQL
-        if ( $mysqli->query('UPDATE docs SET nom = \''.$mysqli->real_escape_string($nom)."' WHERE id = $id") )  {
+        if ( $mysqli->query('UPDATE docs SET nom = \''.$mysqli->real_escape_string($nom)."', nom_nat = ZPAD(nom) WHERE id = $id") )  {
           exec('mv documents/'.escapeshellarg("${doc['lien']}/${doc['nom']}${doc['ext']}").' documents/'.escapeshellarg("${doc['lien']}/$nom${doc['ext']}"));
-          $mysqli->query('ALTER TABLE docs ORDER BY parents,nom');
+          $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
           $message = " Le nom du document <em>$nom</em> a bien été modifié.";
           $doc['nom'] = $nom;
         }
@@ -197,7 +235,7 @@
             $champ = ( $protection < 2 ) ? 'nbdoc_v' : 'nbdoc_nv';
             $mysqli->query("UPDATE reps SET $champ = ($champ -1) WHERE id = ${doc['parent']}");
             $mysqli->query("UPDATE reps SET $champ = ($champ + 1) WHERE id = $parent");
-            $mysqli->query('ALTER TABLE docs ORDER BY parents,nom');
+            $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
             $message .= " Le document <em>${doc['nom']}</em> a bien été déplacé.";
           }
           else
@@ -213,13 +251,15 @@
           $r = $resultat->fetch_assoc();
           $resultat->free();
           $path = $mysqli->real_escape_string("${r['path']}/${doc['nom']}");
+          $icone = array_key_exists(strtolower($doc['ext']),$icones) ? $icones[strtolower($doc['ext'])] : 'defaut';
           // Document auparavant non visible
           if ( $doc['protection'] == 2 )
-            recent($mysqli,3,$id,$path,"download?id=$id","<p>Nouveau document&nbsp;: $path".$mysqli->real_escape_string($doc['ext']).'</p>');
+            recent($mysqli,3,$id,"<img class=\"icone\" src=\"icones/$icone.png\"> $path","download?id=$id","<p>Nouveau document&nbsp;: <a href=\"download?id=$id\">$path</a></p>");
           // Document auparavant visible : on met à jour les chemins, sans mettre en avant le document
           // Remarque : le RSS n'est pas modifié, le sera leur d'une nouvelle information récente
+          // Le lien de téléchargement est de toutes façons inchangé
           else
-            $mysqli->query("UPDATE recents SET texte = REPLACE(texte,titre,'$path'), titre = '$path' WHERE id = 3000+$id");
+            $mysqli->query("UPDATE recents SET texte = '<p>Nouveau document&nbsp;: <a href=\"download?id=$id\">$path</a></p>', titre = '<img class=\"icone\" src=\"icones/$icone.png\"> $path' WHERE id = 3000+$id");
         }
         // Si $protection = 2, on cherche à supprimer.
         else
@@ -267,7 +307,8 @@
           $r = $resultat->fetch_assoc();
           $resultat->free();
           $path = $mysqli->real_escape_string("${r['path']}/${doc['nom']}");
-          recent($mysqli,3,$id,$path,"download?id=$id","<p>Nouvelle version du document&nbsp;: $path".$mysqli->real_escape_string($doc['ext'])."</p>");
+          $icone = array_key_exists(strtolower($doc['ext']),$icones) ? $icones[strtolower($doc['ext'])] : 'defaut';
+          recent($mysqli,3,$id,"<img class=\"icone\" src=\"icones/$icone.png\"> $path","download?id=$id","<p>Nouvelle version du document&nbsp;: <a href=\"download?id=$id\">$path</a></p>");
         }
         $message = "Le document <em>${doc['nom']}</em> a bien été mis à jour.";
       }
@@ -301,9 +342,10 @@
       // Écriture MySQL
       if ( $mysqli->query("INSERT INTO docs SET parent = $rid, parents = '${r['parents']},$rid',
                            matiere = ${r['matiere']}, nom = '".$mysqli->real_escape_string($nom)."',
-                           upload = DATE(NOW()), taille = '$taille', lien = '$lien', ext='".$mysqli->real_escape_string($ext)."', protection = $protection") )  {
+                           nom_nat = ZPAD(nom), upload = DATE(NOW()), taille = '$taille', lien = '$lien',
+                           ext='".$mysqli->real_escape_string($ext)."', protection = $protection") )  {
         $id = $mysqli->insert_id;
-        $mysqli->query('ALTER TABLE docs ORDER BY parents,nom');
+        $mysqli->query('ALTER TABLE docs ORDER BY parents,nom_nat');
         $message = "Le document <em>$nom</em> a bien été mis en ligne.";
         // Mise à jour du répertoire
         $champ = ( $protection < 2 ) ? 'nbdoc_v' : 'nbdoc_nv';
@@ -315,7 +357,8 @@
           $r = $resultat->fetch_assoc();
           $resultat->free();
           $path = $mysqli->real_escape_string("${r['path']}/$nom");
-          recent($mysqli,3,$id,$path,"download?id=$id","<p>Nouveau document&nbsp;: $path".$mysqli->real_escape_string($ext).'</p>');
+          $icone = array_key_exists(strtolower($ext),$icones) ? $icones[strtolower($ext)] : 'defaut';
+          recent($mysqli,3,$id,"<img class=\"icone\" src=\"icones/$icone.png\"> $path","download?id=$id","<p>Nouveau document&nbsp;: <a href=\"download?id=$id\">$path</a></p>");
         }
       }
       else  {
@@ -426,80 +469,11 @@
       }
 
       // Documents
-      $resultat = $mysqli->query("SELECT id, nom, taille, DATE_FORMAT(upload,'%d/%m/%Y') AS upload, ext, protection FROM docs WHERE parent = $rid AND (protection < 2 OR ".var_export($admin,true).')');
+      $resultat = $mysqli->query("SELECT id, nom, taille, DATE_FORMAT(upload,'%d/%m/%Y') AS upload, LOWER(ext) AS ext, protection FROM docs WHERE parent = $rid AND (protection < 2 OR ".var_export($admin,true).')');
       if ( $resultat->num_rows )  {
+        $icones = $GLOBALS['icones'];
         while ( $r = $resultat->fetch_assoc() )  {
-          switch ( $r['ext'] )  {
-            case '.pdf':
-              $icone = 'pdf';
-              break;
-            case '.doc':
-            case '.odt':
-            case '.docx':
-              $icone = 'doc';
-              break;
-            case '.xls':
-            case '.ods':
-            case '.xlsx':
-              $icone = 'xls';
-              break;
-            case '.ppt':
-            case '.odp':
-            case '.pptx':
-              $icone = 'ppt';
-              break;
-            case '.jpg':
-            case '.jpeg':
-            case '.png':
-            case '.gif':
-            case '.svg':
-            case '.tif':
-            case '.tiff':
-            case '.bmp':
-            case '.ps':
-            case '.eps':
-              $icone = 'jpg';
-              break;
-            case '.py':
-              $icone = 'python';
-              break;
-            case '.avi':
-            case '.mpeg':
-            case '.mpg':
-            case '.wmv':
-            case '.mp4':
-            case '.ogv':
-            case '.qt':
-            case '.mov':
-            case '.mkv':
-              $icone = 'avi';
-              break;
-            case '.mp3':
-            case '.ogg':
-            case '.oga':
-            case '.wma':
-            case '.wav':
-            case '.ra':
-            case '.rm':
-              $icone = 'mp3';
-              break;
-            case '.txt':
-            case '.rtf':
-              $icone = 'txt';
-              break;
-            case '.zip':
-            case '.rar':
-            case '.7z':
-              $icone = 'zip';
-              break;
-            case '.exe':
-            case '.sh':
-            case '':
-              $icone = 'exe';
-              break;
-            default :
-              $icone = 'defaut';
-          }
+          $icone = array_key_exists($r['ext'],$icones) ? $icones[$r['ext']] : 'defaut';
           if ( $admin )  {
             $id = $r['id'];
             if ( $r['protection'] == 1 )
diff -urN cahier-de-prepa3.0.3/download.php cahier-de-prepa3.1.0/download.php
--- cahier-de-prepa3.0.3/download.php	2013-08-20 21:38:10.493111597 +0200
+++ cahier-de-prepa3.1.0/download.php	2013-09-04 22:14:23.390653290 +0200
@@ -162,8 +162,8 @@
 
     // Mise à disposition du fichier
     header("Content-Type: $type");
-    header("Content-Disposition: attachment; filename=\"${f['nom']}${f['ext']}\"");
-    header("Location: documents/${f['lien']}/${f['nom']}${f['ext']}");
+    header('Content-Disposition: attachment; filename="'.rawurlencode($f['nom']).$f['ext'].'"');
+    header("Location: documents/${f['lien']}/".rawurlencode($f['nom']).$f['ext']);
   }
 }
 ?>
diff -urN cahier-de-prepa3.0.3/haut.php cahier-de-prepa3.1.0/haut.php
--- cahier-de-prepa3.0.3/haut.php	2013-08-27 08:41:26.534973939 +0200
+++ cahier-de-prepa3.1.0/haut.php	2013-10-24 16:06:41.277840487 +0200
@@ -12,7 +12,7 @@
   <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
   <link rel="stylesheet" href="css/style.css?v=4" type="text/css" media="screen">
   <link rel="stylesheet" href="css/print.css" type="text/css" media="print">
-  <link rel="stylesheet" href="css/couleurs.css?v=3" type="text/css" media="screen">
+  <link rel="stylesheet" href="css/couleurs.css?v=4" type="text/css" media="screen">
   <script type="text/javascript" src="js/jquery.js"></script>
   <script type="text/javascript" src="/MathJax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
 <?php
@@ -181,11 +181,11 @@
   if ( $resultat->num_rows )  {
     $aff = '';
     while ( $r = $resultat->fetch_assoc() )
-      $aff .= "\n    <a href=\"${r['lien']}\">${r['titre']}</a>";
+      $aff .= "\n    <a href=\"${r['lien']}\" title=\"".substr($r['titre'],strpos($r['titre'],'>')+2)."\">${r['titre']}</a>";
     $resultat->free();
     echo <<<FIN
   <div id="recent">
-    <h3>Informations récentes&nbsp;<a href="rss" id="rss"><img src="icones/rss.png" alt="Flux RSS"></a></h3>$aff
+    <h3><a href="rss" id="rss"><img class="icone" src="icones/rss.png" alt="Flux RSS"></a> Infos récentes </h3>$aff
   </div>
 
 
Les fichiers binaires cahier-de-prepa3.0.3/icones/big/colle.png et cahier-de-prepa3.1.0/icones/big/colle.png sont différents
Les fichiers binaires cahier-de-prepa3.0.3/icones/big/info.png et cahier-de-prepa3.1.0/icones/big/info.png sont différents
Les fichiers binaires cahier-de-prepa3.0.3/icones/colle.png et cahier-de-prepa3.1.0/icones/colle.png sont différents
Les fichiers binaires cahier-de-prepa3.0.3/icones/info.png et cahier-de-prepa3.1.0/icones/info.png sont différents
diff -urN cahier-de-prepa3.0.3/index.php cahier-de-prepa3.1.0/index.php
--- cahier-de-prepa3.0.3/index.php	2013-08-28 08:40:37.881737193 +0200
+++ cahier-de-prepa3.1.0/index.php	2013-10-24 12:04:12.585374927 +0200
@@ -75,7 +75,7 @@
           $message = 'L\'information a bien été modifiée.';
           // Ajout d'une information récente si information diffusée
           if ( !$r['cache'] )
-            recent($mysqli,1,$id,"Info : $titre",$lien_recent,$texte);
+            recent($mysqli,1,$id,"<img class=\"icone\" src=\"icones/info.png\"> $titre",$lien_recent,$texte);
         }
         else
           $message = 'L\'information n\'a pas pu être modifiée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
@@ -87,7 +87,7 @@
             $message = 'L\'information a bien été ajoutée.';
             // Ajout d'une information récente si information diffusée
             if ( !$cache )
-              recent($mysqli,1,$mysqli->insert_id,"Info : $titre",$lien_recent,$texte);
+              recent($mysqli,1,$mysqli->insert_id,"<img class=\"icone\" src=\"icones/info.png\"> $titre",$lien_recent,$texte);
             $mysqli->query('ALTER TABLE infos ORDER BY page,ordre');
         }
         else
@@ -114,7 +114,7 @@
         if ( $mysqli->query("UPDATE infos SET cache = 0 WHERE id = $id") )  {
           $message = 'L\'information a bien été diffusée, elle apparaît désormais sur la partie publique.';
           // Ajout d'information récente
-          recent($mysqli,1,$id,'Info : '.$mysqli->real_escape_string($r['titre']),$lien_recent,$mysqli->real_escape_string($r['texte']));
+          recent($mysqli,1,$id,'<img class="icone" src="icones/info.png"> '.$mysqli->real_escape_string($r['titre']),$lien_recent,$mysqli->real_escape_string($r['texte']));
         }
         else
           $message = 'L\'information n\'a pas pu être diffusée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
@@ -230,7 +230,7 @@
   <form action="?$p$urladmin" method="post">
     <input class="bouton" type="submit" name="modifie" value="Valider" title="Valider les modifications de la page">
     <h3>Ajouter une nouvelle information</h3>
-    <input class="ligne" type="text" name="titre" size=50 maxlength=65533 value="Titre de l'information">
+    <p class="transparent"><input class="ligne" type="text" name="titre" size=50 maxlength=65533 value="Titre de l'information"></p>
     <textarea name="texte" rows="10" cols="100">&lt;p&gt;Texte de l'information&lt;/p&gt;</textarea>
     <p class="ligne"><label for="cache">Ne pas diffuser sur la partie publique&nbsp;: </label><input type="checkbox" id="cache" name="cache" value="1"></p>
     <input type="hidden" name="id" value="0">
@@ -264,7 +264,7 @@
       <input type="submit" name="modifie" value="Valider" title="Valider les modifications sur le titre ou le texte">$monte$descend$cache
       <input type="submit" name="supprime" value="Supprimer" title="Supprimer l'information">
     </p>
-    <input class="ligne" type="text" name="titre" size=50 maxlength=65533 value="${r['titre']}">
+    <p class="transparent"><input class="ligne" type="text" name="titre" size=50 maxlength=65533 value="${r['titre']}"></p>
     <textarea name="texte" rows="10" cols="100">${r['texte']}</textarea>
     <input type="hidden" name="id" value="${r['id']}">
   </form>
diff -urN cahier-de-prepa3.0.3/installation.php cahier-de-prepa3.1.0/installation.php
--- cahier-de-prepa3.0.3/installation.php	2013-08-28 15:28:12.146519732 +0200
+++ cahier-de-prepa3.1.0/installation.php	2013-10-23 22:15:24.315783616 +0200
@@ -202,7 +202,7 @@
   `ordre` tinyint(2) unsigned NOT NULL,
   `titre` varchar(50) NOT NULL,
   `cle` varchar(20) NOT NULL,
-  `h_fin` tinyint(1) unsigned NOT NULL,
+  `deb_fin_pour` tinyint(1) unsigned NOT NULL,
   KEY `matiere` (`matiere`)
 ) ENGINE=MyISAM DEFAULT CHARSET=utf8;
 
@@ -239,13 +239,15 @@
   `parents` varchar(50) NOT NULL,
   `matiere` tinyint(2) unsigned NOT NULL,
   `nom` varchar(100) NOT NULL,
+  `nom_nat` VARCHAR(100) NOT NULL,
   `upload` date NOT NULL,
   `taille` varchar(12) NOT NULL,
   `lien` char(15) NOT NULL,
   `ext` varchar(5) NOT NULL,
   `protection` tinyint(1) unsigned NOT NULL,
   KEY `parent` (`parent`),
-  KEY `matiere` (`matiere`)
+  KEY `matiere` (`matiere`),
+  KEY `nom_nat` (`nom_nat`)
 ) ENGINE=MyISAM  DEFAULT CHARSET=utf8;
 
 CREATE TABLE `recents` (
@@ -277,14 +279,14 @@
 INSERT INTO pages (ordre,cle,nom,titre,bandeau,protection)
   VALUES (1,'accueil','Accueil','La classe $c du lycée $l','Dernières informations importantes',0);
 TRUNCATE `cdt-types`;
-INSERT INTO `cdt-types` (`matiere`, `ordre`, `cle`, `titre`, `h_fin`) VALUES
+INSERT INTO `cdt-types` (`matiere`, `ordre`, `cle`, `titre`, `deb_fin_pour`) VALUES
 (1, 1, 'cours', 'Cours', 1),
 (1, 2, 'TD', 'Séance de travaux dirigés', 1),
 (1, 3, 'TP', 'Séance de travaux pratiques', 1),
 (1, 4, 'DS', 'Devoir surveillé', 1),
 (1, 5, 'interros', 'Interrogation de cours', 0),
 (1, 6, 'distributions', 'Distribution de document', 0),
-(1, 7, 'DM', 'Devoir maison', 0);
+(1, 7, 'DM', 'Devoir maison', 2);
 
 TRUNCATE semaines;
 
diff -urN cahier-de-prepa3.0.3/js/timeout.js cahier-de-prepa3.1.0/js/timeout.js
--- cahier-de-prepa3.0.3/js/timeout.js	2013-01-11 16:15:09.000000000 +0100
+++ cahier-de-prepa3.1.0/js/timeout.js	2013-10-23 16:34:28.399129024 +0200
@@ -5,7 +5,7 @@
 <form id="formlogin">\
   <p class="ligne"><label for="login">Nom d\'utilisateur&nbsp;: </label><input type="text" name="login" id="logintmp"></p>\
   <p class="ligne"><label for="motdepasse">Mot de passe&nbsp;: </label><input type="password" name="motdepasse" id="motdepassetmp"></p>\
-  <p><input type="submit" name="Ok" id="connect" value="Envoyer"></p>\
+  <p><input type="submit" value="Envoyer"></p>\
 </form>';
 
 // Affichage des messages
@@ -14,12 +14,11 @@
   // Suppression de l'éventuelle attente
   try{ window.clearTimeout(timeout); } catch(e){}
   timeout = window.setTimeout( function() {
-    $('#message').empty().html(html1).show(200);
+    $('#message').html(html1).show(200);
     $("#connect").click( function() { connect(); return false; });
-    window.clearTimeout(timeout);
     timeout = window.setTimeout( function() {
-      $('#message').empty().html(html2);
-      $("#connect").click( function() { connect(); return false; });
+      $('#message').html(html2);
+      $('#formlogin').submit( function() { connect(); return false; });
     } , 300000);
   } , 600000);
 }
@@ -38,7 +37,7 @@
           if ( data.etat == 1 )  { afficher_timeout(); }
           else  {
             $('#message').html(html2);
-            $("#connect").click( function() { connect(); return false; });
+            $('#formlogin').submit( function() { connect(); return false; });
           }
         },
         "json");
diff -urN cahier-de-prepa3.0.3/MAJSQL.sql cahier-de-prepa3.1.0/MAJSQL.sql
--- cahier-de-prepa3.0.3/MAJSQL.sql	2013-08-28 09:05:07.693784227 +0200
+++ cahier-de-prepa3.1.0/MAJSQL.sql	2013-10-25 11:23:55.444062389 +0200
@@ -39,3 +39,65 @@
 ALTER TABLE reps CHANGE nbfic nbdoc_v TINYINT( 2 ) UNSIGNED NOT NULL;
 ALTER TABLE reps ADD nbdoc_nv TINYINT( 2 ) UNSIGNED NOT NULL;
 UPDATE reps SET nbdoc_nv = ( SELECT COUNT(docs.id) FROM docs WHERE docs.parent = reps.id AND docs.protection = 2 );
+
+-- 
+-- Voilà les modifications à effectuer sur chaque base pour passer de Cahier de
+-- Prépa 3.0.3 à Cahier de Prépa 3.1.0.
+-- 
+
+ALTER TABLE `cdt-types` CHANGE h_fin deb_fin_pour TINYINT( 1 ) UNSIGNED NOT NULL;
+UPDATE `cdt-types` SET deb_fin_pour = 2 WHERE MOD(id,7) = 0;
+UPDATE cdt AS c,`cdt-types` AS ct SET c.h_debut = '0:00' WHERE c.type = ct.id AND ct.deb_fin_pour = 2;
+UPDATE cdt AS c,`cdt-types` AS ct SET c.h_fin = '0:00' WHERE c.type = ct.id AND ct.deb_fin_pour != 1;
+UPDATE cdt AS c,`cdt-types` AS ct SET c.pour = '0000-00-00' WHERE c.type = ct.id AND ct.deb_fin_pour != 2;
+ALTER TABLE cdt ORDER BY jour,matiere,pour,h_debut,h_fin,type;
+ALTER TABLE docs ADD nom_nat VARCHAR( 100 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL AFTER nom;
+ALTER TABLE docs ADD INDEX ( nom_nat );
+DROP FUNCTION IF EXISTS ZPAD;
+DELIMITER $$
+CREATE FUNCTION ZPAD(s VARCHAR(100))
+  RETURNS VARCHAR(100)
+BEGIN
+  DECLARE i INT DEFAULT 1;
+  DECLARE n INT DEFAULT 1;
+  WHILE i <= LENGTH(s) DO
+    IF FIND_IN_SET(SUBSTRING(s,i,1),"0,1,2,3,4,5,6,7,8,9") THEN
+      SET n = i + 1;
+      WHILE FIND_IN_SET(SUBSTRING(s,n,1),"0,1,2,3,4,5,6,7,8,9") DO
+        SET n = n + 1;
+      END WHILE;
+      SET s = CONCAT(LEFT(s,i-1),REPEAT("0",10-n+i),RIGHT(s,CHAR_LENGTH(s)+1-i));
+      SET i = i + 10;
+    END IF;
+    SET i = i + 1;
+  END WHILE;
+  RETURN s;
+END
+$$
+DELIMITER ;
+UPDATE docs SET nom_nat=ZPAD(nom);
+DROP FUNCTION ZPAD;
+ALTER TABLE docs ORDER BY parents, nom_nat;
+UPDATE recents SET titre = CONCAT('<img class="icone" src="icones/info.png"> ',SUBSTRING(titre,8,CHAR_LENGTH(titre))) WHERE id < 2000;
+UPDATE recents SET titre = CONCAT('<img class="icone" src="icones/colle.png"> ',titre) WHERE id > 2000 AND id < 3000;
+UPDATE recents AS r, docs AS d SET 
+  texte = CONCAT('<p>Nouveau document&nbsp;: <a href="download?id=',d.id,'">',r.titre,'</a></p>'),
+  titre  = CONCAT('<img class="icone" src="icones/',
+  CASE LOWER(d.ext)
+    WHEN '.pdf' OR '.ps' THEN 'pdf' 
+    WHEN '.doc' OR '.odt' OR '.docx' THEN 'doc'
+    WHEN '.xls' OR '.ods' OR '.xlsx' THEN 'xls'
+    WHEN '.ppt' OR '.odp' OR '.pptx' THEN 'ppt'
+    WHEN '.jpg' OR '.jpeg' OR '.png' OR '.gif' OR '.svg' OR '.tif' OR '.tiff' OR '.bmp' OR '.ps' OR '.eps' THEN 'jpg'
+    WHEN '.py' THEN 'python'
+    WHEN '.avi' OR '.mpeg' OR '.mpg' OR '.wmv' OR '.mp4' OR '.ogv' OR '.qt' OR '.mov' OR '.mkv' OR 'flv' THEN 'avi'
+    WHEN '.mp3' OR '.ogg' OR '.oga' OR '.wma' OR '.wav' OR '.ra' OR '.rm' THEN 'mp3'
+    WHEN '.txt' OR '.rtf' THEN 'txt'
+    WHEN '.zip' OR '.rar' OR '.7z' THEN 'zip'
+    WHEN '.exe' OR '.sh' OR '.ml' OR '.mw' OR '' THEN 'exe'
+    ELSE 'defaut' END
+  ,'.png"> ',r.titre)
+  WHERE r.id > 3000 AND d.id = r.id - 3000;
+-- À effectuer avec les droits root
+UPDATE mysql.db SET Create_routine_priv = 'Y' WHERE db.Db = '[base]' AND db.User = '[base]-adm';
+FLUSH PRIVILEGES;
diff -urN cahier-de-prepa3.0.3/matieres.php cahier-de-prepa3.1.0/matieres.php
--- cahier-de-prepa3.0.3/matieres.php	2013-08-30 21:13:10.300711697 +0200
+++ cahier-de-prepa3.1.0/matieres.php	2013-10-21 01:02:05.843809234 +0200
@@ -51,14 +51,14 @@
         $message = ( $mysqli->query("INSERT INTO matieres SET cle = '$cle', nom = '$nom', colles = '$colles', cdt = '$cdt', docs = 0, ordre = ((SELECT MAX(m.ordre) FROM matieres AS m)+1)")
                   && ( $id = $mysqli->insert_id )
                   && $mysqli->query("INSERT INTO reps SET parent = 0, parents = 0, nom = '$nom', matiere = $id, nbrep = 0, nbdoc_v = 0, nbdoc_nv = 0, protection = 0")
-                  && $mysqli->query("INSERT INTO `cdt-types` (matiere, ordre, cle, titre, h_fin) VALUES
+                  && $mysqli->query("INSERT INTO `cdt-types` (matiere, ordre, cle, titre, deb_fin_pour) VALUES
                                                              ($id, 1, 'cours', 'Cours', 1),
                                                              ($id, 2, 'TD', 'Séance de travaux dirigés', 1),
                                                              ($id, 3, 'TP', 'Séance de travaux pratiques', 1),
                                                              ($id, 4, 'DS', 'Devoir surveillé', 1),
                                                              ($id, 5, 'interros', 'Interrogation de cours', 0),
                                                              ($id, 6, 'distributions', 'Distribution de document', 0),
-                                                             ($id, 7, 'DM', 'Devoir maison', 0)")
+                                                             ($id, 7, 'DM', 'Devoir maison', 2)")
         ) ? 'La matière <em>'.stripslashes($nom).'</em> a bien été ajoutée.' : 'La matière <em>'.stripslashes($nom).'</em> n\'a pas pu être ajoutée. Erreur MySQL n°'.$mysqli->errno.', «'.$mysqli->error.'».';
       }
     }
diff -urN cahier-de-prepa3.0.3/textarea.js.php cahier-de-prepa3.1.0/textarea.js.php
--- cahier-de-prepa3.0.3/textarea.js.php	2013-08-30 21:10:07.096705834 +0200
+++ cahier-de-prepa3.1.0/textarea.js.php	2013-10-22 12:10:50.711858045 +0200
@@ -46,6 +46,7 @@
   $('\
   <div id="js_controls">\
     <div id="aide_js">\
+      <h4>Aide et explications <span></span> <input type="button" id="js_preview" value="Prévisualiser le texte"></h4>\
       <p>Le texte doit être écrit en HTML&nbsp;: toute mise en forme est indiquée par deux balises, de début comme &lt;h3&gt; pour un gros titre, de fin comme &lt;/h3&gt;. Les boutons ci-dessus aident à «&nbsp;encadrer&nbsp;» un texte sélectionné des balises correctes.</p>\
       <p>Comme en HTML, les retours à la ligne et les espaces multiples ne comptent pas. Un retour à la ligne dans un paragraphe (&lt;p&gt;Bla bla&lt;/p&gt;) ne crée pas un retour à la ligne visible au final. Pour ce faire, on peut utiliser la balise unique &lt;br&gt;, mais il vaut mieux mettre chaque paragraphe entre balises &lt;p&gt; et &lt;/p&gt;. Les espaces en début de ligne, de même, n\'apparaissent pas sur le site public et ne servent qu\'à la lisibilité ici.</p>\
       <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 $...$). Il faut ensuite taper du code en LaTeX à l\'intérieur. La prévisualisation est impossible&nbsp;: il faut valider le texte et aller voir le site public pour vérifier ce que l\'on a tapé.</p>\
@@ -89,7 +90,6 @@
   }
 
   // Aide
-  $('#aide_js').prepend("<h4>Aide et explications <span></span></h4>");
   $('#aide_js h4 span').css('cursor','pointer').click( function () {
     $(this).parent().parent().find('p').toggle();
     $(this).text($(this).text() == '[déplier]' ? '[replier]' : '[déplier]');
@@ -104,6 +104,18 @@
     $('#aide_js').find('p').hide();
     $('#aide_js h4 span').text('[déplier]');
   });
+
+  // Prévisualisation
+  $('<div id="preview_fond"></div>').appendTo('body');
+  $('<div class="item admin" id="preview"><h2>Prévisualisation</h2><div></div><p>Cliquer n\'importe où pour revenir à l\'édition</p></div>').appendTo('body');
+  $('#preview_fond,#preview').hide().click(function() { $('#preview_fond,#preview').hide(); });
+  $('#js_preview').click(function() {
+    $('#preview>div').html($('#active').val());
+    $('#preview_fond,#preview').show();
+    MathJax.Hub.Queue(["Typeset",MathJax.Hub,"preview"]);
+    
+  });
+  
 <?php
   if ( !empty($docs) )  {
     echo '
