Un petit calendrier light

Eléphanteau du PHP | 32 Messages

02 mars 2005, 18:19

Je vous laisse un bout de code.
Je dois faire un module de réservation de salles pour mon boulot, et il faut un calendrier.
j'en avais déjà un, mais super compliqué, avec des trucs dans tous les sens.
Donc je me suis penché dessus cet après-midi en essayant de faire un truc hyper compact.
Il tient en 15 lignes de code...
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<title>Calendrier</title>
</head>
<body>
<?
setlocale(LC_TIME, "fr");
//Si le mois et l'année ne sont pas demandés, alors on utilise le mois en cours
if (!isset($_GET['mois'])) $_GET['mois'] = date("m");
if (!isset($_GET['annee'])) $_GET['annee'] = date("Y");
//On calcule les mois et années pour précédent et suivant
list($mois_suivant,$annee_suivant) = explode("-",strftime("%m-%Y",mktime(0,0,0,$_GET['mois']+1,1,$_GET['annee'])));
list($mois_precedent,$annee_precedent) = explode("-",strftime("%m-%Y",mktime(0,0,0,$_GET['mois']-1,1,$_GET['annee'])));
//Nettoyage de l'URL
$url = ereg_replace("mois=".$_GET['mois']."&annee=".$_GET['annee'],"",$_SERVER['QUERY_STRING']);
if($url != '') $url.="&";
?>
<table width="140" border="0" cellspacing="1" cellpadding="5">
  <tr>
    <td><a href="?<? echo $url; ?>mois=<? echo $mois_precedent; ?>&annee=<? echo $annee_precedent; ?>">-</a></td>
    <td colspan="5" align="center"><? echo ucwords(strftime("%B %Y",mktime(0,0,0,$_GET['mois'],1,$_GET['annee']))); ?></td>
    <td><a href="?<? echo $url; ?>mois=<? echo $mois_suivant; ?>&annee=<? echo $annee_suivant; ?>">+</a></td>
  </tr>
  <tr>
    <td width="20">Lu</td>
    <td width="20">Ma</td>
    <td width="20">Me</td>
    <td width="20">Je</td>
    <td width="20">Ve</td>
    <td width="20">Sa</td>
    <td width="20">Di</td>
  </tr>
<?
/*
On calcule la position de chaque jour dans la semaine.
Sachant que Lundi = 0 et Dimanche = 6.
*/
for($i='1'; $i <= cal_days_in_month(CAL_GREGORIAN,$_GET['mois'],$_GET['annee']); $i++)
	{
	$position_jour_semaine[] = strftime("%w",mktime(0,0,0,$_GET['mois'],$i,$_GET['annee']));
	};
//On va gérer l'affichage du calendrier

for($i='0', $case_tableau='1'; $i<sizeof($position_jour_semaine); $i++)
	{
	if($case_tableau=='8') $case_tableau='1';
	$jour = $position_jour_semaine[$i];
	if($jour=='0') $jour='7';
	if($case_tableau=='1') echo '<tr>';
	//On a 7 cases, il faut vérifier que la valeur de $position_jour_semaine vaut $case_tableau pour l'afficher
	//On progresse façon "bataille navale"
	//Tant que notre jour de début n'est pas égal à la case du tableau
	while($jour!=$case_tableau)
		{
		//On rempli la case de vide
		echo '<td>&nbsp;</td>';
		//Et on avance d'une case
		$case_tableau++;
		};
	//Par contre quand le jour est égal à la case du tableau
	if($jour==$case_tableau)
		{
		//On écrit le jour du mois dedans
		if(($i+1==date('d')) AND ($_GET['mois']==date('m')))
			{
			echo '<td><strong>'.($i+1).'</strong></td>';
			}
			else
			{
			echo '<td>'.($i+1).'</td>';
			};
		//On avance d'une case dans notre tableau
		$case_tableau++;
		};
	//Si on arrive à 8 c'est qu'on a fini la ligne, donc on ferme la balise
	if($case_tableau=='8') echo '</tr>';
	};
//On calcule pour les cas où on sort avant d'arriver à 8 dans le tableau.	
while($case_tableau < '8') 
	{
	echo '<td>&nbsp;</td>';
	$case_tableau++;
	};
?>
</tr>
</table>
</body>
</html>
Il reste à peaufiner le passage d'un mois à un autre (un petit mktime rapide devrait le faire).
La mise en page est rustre, je sais.

Voilà !
Si ça peut aider des gens qui n'ont pas envie d'un truc massif.
Si vous ne comprenez pas tout, je peux expliquer le total, c'est très tortueux comme raisonnement :)

Edit du 03/03:
- Tableau plus joli
- Prise en compte du + et du -
- Majuscule sur le nom du mois
- Prise en compte de l'URL d'appel: les paramètres de mois et d'année sont placés en fin d'URL

hrz
Eléphant du PHP | 52 Messages

04 mars 2005, 18:29

15 lignes de codes :^o
j'en compte deja une trentaine rien que pour l'affichage
faut j'retourne a l'ecole alors
sinon pourquoi pas ca fait 2 solution ici sur le sujet

Eléphanteau du PHP | 32 Messages

07 mars 2005, 13:50

Autant pour moi, la prochaine fois j'arrêterais de bosser pour compter le nombre de lignes :-#
Je sens comme un reproche parce qu'une fonction à déjà été proposée...
Donc je m'excuse de proposer le 250.000.001 bout de code faisant calendrier. [-(

hrz
Eléphant du PHP | 52 Messages

07 mars 2005, 20:49

pas un reproche juste un gag :? bon bof ok
250.000.001
ouf! t'a mieux regarder que moi
la preuve qu'il y a toujours 1000 & 1 facons de faire meme si les idees se recoupent au final
Donc je me suis penché dessus cet après-midi en essayant de faire un truc hyper compact.
c'est plus cette partie qui m'a fait reagir (de travers :cry: )

Mammouth du PHP | 859 Messages

08 mars 2005, 14:24

En même temps, avec l'indentation et les sauts de lignes pour que tout soit bien aéré, faire 15 lignes de codes pour un calendrier ça me paraît mission impossible.
function colordate($recupi)
			{
				//Jour actuel
				$jour = date("d");
				if ($jour == $recupi)
					{
						//Date colorée
						$date = "<span style='color: #FC5301'><b>".$recupi."</b></span>";
					}
				else
					{
						//Date non colorée
						$date = "<span style='color: #333333'>".$recupi."</span>";
					}
				return($date);
			}
15 lignes pour colorer la date actuelle donc bon...

Eléphanteau du PHP | 32 Messages

08 mars 2005, 15:31

Autant pour moi si c'était du second degré... :oops:
J'ai mis 15 lignes par opposition au 300-400 lignes habituelles d'affichage d'un calendrier éclatées sur 4-5 fichiers.
Le dernier que j'ai trouvé fait plus de 100 lignes et uniquement du PHP...
Avec des fonctions et des trucs compliqués de calcul de date, qui en plus me balancent 30 jours au mois de Février... ça fait tâche.
Je voulais juste un tableau simple, light sans fioriture.

Mammouth du PHP | 859 Messages

08 mars 2005, 16:50

Code : Tout sélectionner

setlocale(LC_TIME, "fr");
Mets ça plutôt sinon tu peux te retrouver avec la date en anglais sur certains hébergeurs :

Code : Tout sélectionner

setlocale(LC_TIME, "fr_FR");

hrz
Eléphant du PHP | 52 Messages

08 mars 2005, 18:18

et si :idea:
peut on faire un calendrier (simple) avec 15 lignes de code !?

- disons avec le code qui tiend dans la largeur d'une page standard
- avec les commentaires sur la meme ligne mais qui peuvent eux depasser la largeur de la page (pas trop quand meme )

- y'a rien a gagner juste le fun et les idees 8)

a vos claviers :!:

Eléphanteau du PHP | 32 Messages

08 mars 2005, 18:21

Code : Tout sélectionner

setlocale(LC_TIME, "fr");
Mets ça plutôt sinon tu peux te retrouver avec la date en anglais sur certains hébergeurs :

Code : Tout sélectionner

setlocale(LC_TIME, "fr_FR");
Le problème c'est que ça ne fonctionne pas sur mon serveur :)
Il faut que je me replonge dans Apache et le php.ini de toute façon, c'est trop le souk.

Sinon, lol l'idée des 15 lignes.
J'aime bien me poser et chercher à faire un truc très court.
Généralement on gagne du temps après pour modifier parce que tout le superflu est passé à la trappe.

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

09 mars 2005, 12:20

15 lignes, tenu:
<?php 
	$m_loc = array(1=>'Janvier', 2=>'Février', 3=>'Mars', 4=>'Avril', 5=>'Mai', 6=>'Juin', 7=>'Juillet', 8=>'Août', 9=>'Septembre', 10=>'Octobre', 11=>'Novembre', 12=>'Décembre');
	$m=(isset($_GET['m'])?$_GET['m']:date('m'))%12; if ($m==0) $m=12; // numéro du mois (vérifié)
	$a=(int)(isset($_GET['a'])?$_GET['a']:date('Y')); if ($a<1970) $a=1970; // année (min 1970, vérifié)
	$nj = date('t', $t=mktime(0, 0, 1, $m, 1, $a)); // $nj = nombre de jours dans le mois, $t = timestamp du 1er jour du moi
	$sb = ( $j = date('w',$t)==0 ? 7 : date('w',$t) ) - 1; // $sb = espaces vides avant le 1er du mois = $j-1; $j = n° du jour (décalé de 1 par rapport à la version anglaise)
	$sa = ($nl=ceil(($nj+$sb)/7))*7 - $nj - $sb; // $sa = espaces vides après le dernier jour du mois; $nl = nombre de lignes dans la table
	$tb = array_fill(0, $nl, array_fill(1,7,'&nbsp;')); // contenu de la table sans aucun jour
	for ($i=1; $i<=$nj; $i++) $tb[floor(($i+$sb-1)/7)][($i+$sb-1)%7+1] = $i; // on met le n° de jour dans les cellules
?>
<table border="1"><tr><th align="center"><?php if ($m>1||$a>1970) { ?><a href="calendrier.php?a=<?=$m==1?$a-1:$a?>&m=<?=$m==1?12:$m-1?>"><</a><?php } ?>
<?=$m_loc[$m]?> <?=$a?> <a href="calendrier.php?a=<?=$m==12?$a+1:$a?>&m=<?=$m==12?1:$m+1?>">></a>
<tr><th>Lundi</th><th>Mardi</th><th>Mercredi</th><th>Jeudi</th><th>Vendredi</th><th>Samedi</th><th>Dimanche</th></tr>
<?php $jc=$a==date('Y')&&$m==date('m')?date('d'):-1; foreach ($tb as $l) { ?><tr><?php foreach ($l as $c) { ?><td<?php if ($c==$jc) { ?> style="background:#E0E0E0"<?php } ?>><?=$c?></td><?php } ?></tr><?php } ?>
</table>
Démo ici: http://naholyr.free.fr/calendrier.php

Mais franchement, c'est à gerber ce code :cry:

P.S: je n'assure pas le support :lol:

Edit: après recompte, la ligne la plus longue (la définition des mois en français) fait 176 caractères, c'est "un peu" long :D Il y aurait bien 2 ou 3 lignes à couper en deux. Mais d'un autre côté j'ai pris une ligne complète pour "</table>", "<?php" et "?>" donc l'honneur est sauf 8)

Administrateur PHPfrance
Administrateur PHPfrance | 11457 Messages

09 mars 2005, 13:28

Naholyr, je n'ai qu'un mot... euh, smiley... à te dire : =D>

Et maintenant... Ben, je vais m'inscrire pour une formation chez Anaska
parce que j'ai quand même un peu de mal à analyser ton code... :lol:

Mammouth du PHP | 859 Messages

09 mars 2005, 14:22

Oui oui c'est bien ce que tout le monde se disait !

Ca tient en 15 lignes mais au prix d'un code horrible :lol:
Modifié en dernier par flitox le 09 mars 2005, 18:12, modifié 1 fois.

Administrateur PHPfrance
Administrateur PHPfrance | 3131 Messages

09 mars 2005, 17:36

Note: j'ai oublié un colspan="7" sur ma première ligne (le mois).

Je pense que si vous prenez juste 5 minutes pour défaire les noeuds (les affectations imbriquées par exemple, ça fait gagner des lignes mais c'est immonde), le principe est assez simple.
C'est même plutot un bon principe: d'abord les calculs, la préparation des données, puis l'affichage (brute) de ces données.

En l'occurence je me fais un tableau de X lignes de 7 colonnes, chaque cellule contenant soit "&nbsp;" (rien dans la cellule, on aurait pu abstraire avec un false, mais j'avais la flemme), soit le numéro du jour du mois correspondant.

Une fois qu'on connait le premier jour du mois, on sait combien de cases "sauter" sur la première ligne, directement en numérotant les jours (1=lundi, 7=dimanche, un simple décalage du résultat de date('w')).

Connaissant ça, on connait le nombre de cases minimum à utiliser avec le nombre total de jours dans le mois. Exemple ce mois-ci (mars 2005): premier jour = jeudi (4), soit 3 cases à sauter, + 31 jours au total, soit au minimum 34 cases à utiliser. On aura donc 5 lignes dans le tableau: on connait le nombre de lignes (5), le nombre de colonnes (7), on remplit tout ça avec des "&nbsp;", et on commence à décompter les jours de 1 à 31 en partant de la 5è case (premier jour = jeudi = 5) avec un bête "for", avec des modulo et des arrondis pour les index du tableau (classique).

Je n'avais pas prévu de commenter autant que ça mais finalement je me rends compte que l'algo n'est pas si inutile ^^ (en particulier la "classique" utilisation des modulo et des arrondis pour les index, qu'on voit à l'école mais qu'on applique rarement).

C'est intéressant parce qu'on utilise rarement cette méthode pour afficher une table avec des cases vides (ce qui arrive souvent) et qu'elle peut avoir ses avantages (en particulier conjointement à une utilisation de templates).

Heu bon je te rends ton topic ménant ^^

Edit: cadeau
<?php

    $m_loc = array(
		 1=>'Janvier', 
		 2=>'Février', 
		 3=>'Mars', 
		 4=>'Avril', 
		 5=>'Mai', 
		 6=>'Juin', 
		 7=>'Juillet', 
		 8=>'Août', 
		 9=>'Septembre', 
		10=>'Octobre', 
		11=>'Novembre', 
		12=>'Décembre'
	);

	// numéro du mois
    $m = isset($_GET['m']) ? $_GET['m'] : date('m');
	// exclure les valeurs en dehors de [ 1 , 12 ]
	$m %= 12;
	if ($m == 0) $m = 12;

	// numéro de l'année
	$a = (int) ( isset($_GET['a']) ? $_GET['a'] : date('Y') );
	// exclure les années < 1970
	if ($a<1970) $a=1970;
	
	// timestamp du 1er du mois à minuit une
	$t = mktime(0, 0, 1, $m, 1, $a);
	
	// nombre de jours dans ce mois
    $nj = date('t', $t);
	
	// n° du premier jour du mois: on décale le résultat anglais (premier=0=dimanche) pour obtenir premier=1=lundi
	$j = date('w', $t);
	if ($j==0) $j = 7; // dimanche=7
	else       $j = $j; // lundi=1 ... samedi=6
	
	// nombre d'espaces à laisser vides avant le premier jour du mois = numéro du jour - 1
	$sb = $j - 1;
	
	// nombre de lignes au total dans la table 
	// sachant qu'il faut placer AU MOINS $nj+$sb cases, et qu'on a 7 colonnes
	$nl = ceil(($nj+$sb)/7);

	// pré-remplissage de la table avec des cases vides (0) partout
    $tb = array_fill(0, $nl, array_fill(1,7,0));
	
	// remplissage avec les n° de jours, en sautant les $sb premières cases
    for ($i=1; $i<=$nj; $i++) {
		$ligne = floor(($i+$sb-1)/7);
		$colonne = ($i+$sb-1)%7 + 1;
		$tb[$ligne][$colonne] = $i;
	}
	
	// mois précédent
	$m_prec = $m==1 ? 12 : $m-1;
	$a_prec = $m==1 ? $a-1 : $a;
	
	// mois suivant
	$m_suiv = $m==12 ? 1 : $m+1;
	$a_suiv = $m==12 ? $a+1 : $a;
	
	// jour en cours (pour surligner la case correspondante)
	// -1 si mois != mois en cours ou année != année en cours
	$jc = $a==date('Y') && $m==date('m') ? date('d') : -1;

?>
<table border="1">
	<tr><th align="center" colspan="7">
		<?php if ($m>1||$a>1970) { ?><a href="calendrier.php?a=<?=$a_prec?>&m=<?=$m_prec?>"><</a><?php } ?>
		<?=$m_loc[$m]?> <?=$a?>
		<a href="calendrier.php?a=<?=$a_suiv?>&m=<?=$m_suiv?>">></a>
	</th></tr>
	<tr>
		<th>Lundi</th>
		<th>Mardi</th>
		<th>Mercredi</th>
		<th>Jeudi</th>
		<th>Vendredi</th>
		<th>Samedi</th>
		<th>Dimanche</th>
	</tr>
	<?php foreach ($tb as $l) { ?>
	<tr>
		<?php foreach ($l as $c) { ?>
		<td<?php if ($c==$jc) { ?> style="background:#E0E0E0"<?php } ?>><?=$c?></td>
		<?php } ?>
	</tr>
	<?php } ?>
</table>

hrz
Eléphant du PHP | 52 Messages

09 mars 2005, 18:45

Image
15 lignes, tenu:
pareil pour moi =D> =D> je dois dire que je l'attendais un peu celle la :
il me semblais bien que certains marchent a la ligne de code :lol:
merci aussi pour le meme code en plus clair. en passant j'ai encore apris quelque chose: j'ai du boulot pour etre a la hauteur Image

Eléphant du PHP | 205 Messages

10 mars 2005, 02:55

Croyez-le ou non, mais j'ai déjà reçu une soumission d'une jeune firme (de débutants) qui disait (je traduis de l'anglais):

Nous sommes spécialisés et nous nous faisons un honneur de rendre notre code aussi compact que lisible... Ainsi, nos tarifs qui ne sont pas horaires mais basés sur chaque ligne de code, sont ainsi des plus avantageux! [SIC]

Après information, on m'avait dit qu'ils chargeaient entre 0,10$ et 0,15$ la ligne de code! Bien sûr, je ne les ai jamais rappelé!

Alors selon cette logique: au plus bas mot, Naholyr aurait pu se faire 1,50$. Wow! :wink:
Si vous pensez que l'éducation coûte cher, essayez l'ignorance!