Souhait
Nous souhaitons afficher tous les événements (publiés) du site sous forme calendaire, en proposant d’abord un affichage par mois, avec possibilité de basculer en affichage par semaine ou par jour.
Pré-requis
- SPIP 3.0.x, en ayant conservé l’organiseur dans plugins-dist.
- Plugin Agenda 3.6.11 minimum.
- Compréhension de la mécanique des squelettes de SPIP.
- Quelques évènements à afficher.
Vous n’avez pas besoin d’installer la librairire FullCalendar : elle est livrée avec SPIP.
Principe de base
Pour afficher notre agenda nous allons :
- créer un squelette agenda.html, avec un
div
dont l’attributid
estagenda
. - appeler dans le squelette le script
fullcalendar
et ses feuilles de styles. - utiliser ce script pour afficher l’agenda dans dans la
div#agenda
. - créer un squelette
agenda.json.html
fournissant au script les données à afficher dans l’agenda.
Fichiers manipulés
Dans cet article nous manipulons deux fichiers squelettes :
-
agenda.html
(qui contient le code nécessaire à l’affichage du calendrier). -
agenda.json.html
(qui nous permet de générer une liste d’événements compatible avec le script fullcalendar).
Si l’un de ces squelette existe déjà, je vous invite à utiliser le mécanisme de surcharge de SPIP.
Création du squelette
Il nous faut créer un squelette agenda.html
complet (à savoir une page SPIP classique avec les balises <head><body>
etc), dans lequel nous mettons un div
dont l’attribut id
est agenda
à l’endroit où nous souhaitons que l’agenda s’affiche.
Au dessus de ce div, nous allons appeler :
- la version compressée du script
fullcalendar
- les styles associés à ce script.
Pour ce faire, nous utilisons la balise #CHEMIN
:
<link rel='stylesheet' type='text/css' href='#CHEMIN{lib/fullcalendar/fullcalendar.css}' />
<script type='text/javascript' src='#CHEMIN{lib/fullcalendar/fullcalendar.min.js}'></script>
<div id="agenda">
</div>
Appel à l’agenda
Nous allons maintenant ajouter les fonctions javascript qui permette d’afficher l’agenda. Pour ce faire, nous allons mettre au dessus du div (cela pourrait être dedans ou en dessous, cela importe peu) le code suivant, que je vais commenter :
<script type="text/javascript">/*<![CDATA[*/
jQuery(document).ready(function() {
jQuery('#agenda').fullCalendar({
editable: false,
events: "[(#URL_PAGE{agenda.json})]",
header: {
left: 'prevYear,prev,next,nextYear today',
center: 'title',
right: 'month,agendaWeek,agendaDay'
},
firstDay: 1,
monthNames:['<:date_mois_1|attribut_html:>','<:date_mois_2|attribut_html:>','<:date_mois_3|attribut_html:>','<:date_mois_4|attribut_html:>','<:date_mois_5|attribut_html:>','<:date_mois_6|attribut_html:>','<:date_mois_7|attribut_html:>','<:date_mois_8|attribut_html:>','<:date_mois_9|attribut_html:>','<:date_mois_10|attribut_html:>','<:date_mois_11|attribut_html:>','<:date_mois_12|attribut_html:>'],
monthNamesShort:['<:date_mois_1_abbr|attribut_html:>','<:date_mois_2_abbr|attribut_html:>','<:date_mois_3_abbr|attribut_html:>','<:date_mois_4_abbr|attribut_html:>','<:date_mois_5_abbr|attribut_html:>','<:date_mois_6_abbr|attribut_html:>','<:date_mois_7_abbr|attribut_html:>','<:date_mois_8_abbr|attribut_html:>','<:date_mois_9_abbr|attribut_html:>','<:date_mois_10_abbr|attribut_html:>','<:date_mois_11_abbr|attribut_html:>','<:date_mois_12_abbr|attribut_html:>'],
dayNames:['<:date_jour_1|attribut_html:>','<:date_jour_2|attribut_html:>','<:date_jour_3|attribut_html:>','<:date_jour_4|attribut_html:>','<:date_jour_5|attribut_html:>','<:date_jour_6|attribut_html:>','<:date_jour_7|attribut_html:>'],
dayNamesShort:['<:date_jour_1_abbr|attribut_html:>','<:date_jour_2_abbr|attribut_html:>','<:date_jour_3_abbr|attribut_html:>','<:date_jour_4_abbr|attribut_html:>','<:date_jour_5_abbr|attribut_html:>','<:date_jour_6_abbr|attribut_html:>','<:date_jour_7_abbr|attribut_html:>'],
buttonText: {
today: '<:date_aujourdhui|attribut_html:>',
month: '<:organiseur:cal_par_mois|attribut_html:>',
day: '<:organiseur:cal_par_jour|attribut_html:>',
week: '<:organiseur:cal_par_semaine|attribut_html:>'
},
weekMode : 'liquid',
loading: function(bool) {
if (bool) $('#calendrier-loading').show();
else $('#calendrier-loading').hide();
},
timeFormat: {
agenda: "H'h'mm{ - H'h'mm}",
'': "H'h'(mm)"
},
axisFormat: "H'h'(mm)",
allDayText:'<:organiseur:cal_jour_entier|attribut_html:>',
columnFormat: {
month: 'ddd',
week: 'ddd d/M',
day: 'dddd d/M'
},
titleFormat: {
month: 'MMMM yyyy',
week: "d [ MMM] [ yyyy]{ '—' d MMM yyyy}",
day: 'dddd d MMM yyyy'
},
dayClick: function(date, allDay, jsEvent, view) {
if(view.name=='month'){
$('.fc-button-agendaWeek').click();
$('#calendrier').fullCalendar( 'gotoDate', date );
}
else
if(view.name=='agendaWeek'){
$('.fc-button-agendaDay').click();
$('#calendrier').fullCalendar( 'gotoDate', date );
}
},
isRTL : [(#LANG_DIR|=={rtl}|?{true,false})]
})
});
/*]]>*/</script>
- l. 2
jQuery(document).ready(function()
signifie qu’à la fin du chargement du document, le navigateur va exécuter la fonction dans les accolades qui suivent. - l. 5
$('#agenda').fullCalendar
signifie que nous allons demander à javascript de modifier lediv
dont l’id est égale àagenda
pour y mettre à la place .…l’agenda. - Le code entre parenthèse puis accolade correspond aux options passées à l’agenda (l. 5-59) :
- l. 6 : on ne peut éditer les évènements depuis l’agenda.
- l. 7 : on récuperera la liste des évènements via un squelette
agenda.json.html
, nous détaillerons ce squelette dans la partie suivante - l. 8-12 : qu’affiche-t-on dans l’entête de l’agenda ? :
- l. 9 : à gauche, on met les boutons de navigation par mois/semaines/jours (selon le type de calendrier) et par années (dans tout les cas).
- l. 10 : au centre, on affiche le titre de l’agenda, correspondant à la période affichée (par ex. « Août 2012 »).
- l. 11 : à droite, on affiche la bascule vers l’agenda en mode mois, semaine ou jour.
- l. 13 : le premier jour de la semaine est le lundi (=1)
- l. 14 : noms des mois, définis avec les chaînes de langues de SPIP.
- l. 15 : noms des mois en abrégé.
- l. 16 : noms des jours.
- l. 17 : nom des jours en abrégé.
- l. 18-23 : textes des boutons.
- l. 24 : selon les mois, on affichera 4, 5 ou 6 semaines, mais en faisant varier visuellement la hauteur des semaines, pour avoir un mois dont la hauteur est constante. Je renvoie à la documentation sur
weekMode
. - l. 25-27 : permet d’afficher un contenu le temps que l’agenda se charge. Nous en parlerons plus loins.
- l. 29-34 : formatage des heures dans l’agenda :
- l. 31 : lorsqu’on est par semaine ou par jour, on affiche l’heure et les minutes.
- l. 33 : dans les autres cas, juste l’heure.
- l. 35 : formatage des heures sur l’axe vertical (pour l’affichage par jours).
- l. 36 : texte indiquant qu’un événement dure une journée entière.
- l. 37-41 : formatage des dates dans les entêtes de colonnes :
- l. 38 : pour l’affichage par mois.
- l. 39 : pour l’affichage par semaines.
- l. 40 : pour l’affichage par jours.
- l. 42-46 : titre de l’agenda :
- l. 43 : lors de l’affichage par mois.
- l. 44 : lors de l’affichage par semaines.
- l. 46 : lors de l’affichage par jours.
- l. 47-57 : action à executer lorsqu’on clique sur un jour.
- l. 58 : notre agenda doit-il se lire de gauche à droite ou de droite à gauche ?
D’autres options sont bien sûr possible : on se reportera à la documentation de FullCalendar.
Sélection des évènements à afficher
Pour pouvoir afficher les évènements, il va falloir nous fabriquer un squelette agenda.json.html
(cf. l. 7) qui retournera les évènements qui nous intéreressent sous forme de donnée JSON.
La page spip.php?page=agenda.json
sera automatiquement appelée par FullCalendar, qui lui passera deux arguments, variant selon la période demandée :
-
start
, correspondant au timestamp de la date de début. -
end
, correspondant au timestamp de la date de fin.
Dans le squelette agenda.json.html
correspondant à cette page, nous pourrons récuperer ces informations via : #ENV{start}
et #ENV{end}
(voir mon article sur la balise #ENV
). On pourrait éventuellement passer d’autres arguments, en appliquant le filtre |parametre_url
sur #URL_PAGE{agenda.json}
.
Voilà un squelette agenda.json.html
basique :
#HTTP_HEADER{Content-Type: application/json; charset=#CHARSET}
[<BOUCLE_evenements(EVENEMENTS){', '}{par date_debut}
{agendafull date_debut,date_fin, periode,
#VAL{Y}|date{#ENV{start}}, #VAL{m}|date{#ENV{start}}, #VAL{d}|date{#ENV{start}},
#VAL{Y}|date{#ENV{end}}, #VAL{m}|date{#ENV{end}}, #VAL{d}|date{#ENV{end}}}
>
[(#ARRAY{id,#ID_EVENEMENT,
title,[(#TITRE|html2unicode|unicode2charset)],
allDay,[(#HORAIRE|=={non}|?{#EVAL{true},#EVAL{false}})],
start,#DATE_DEBUT,
end,#DATE_FIN,
url,#URL_ARTICLE,
description,[(#DESCRIPTIF|html2unicode|unicode2charset)]}|json_encode)]
</BOUCLE_evenements>]
Je commente rapidement ce squelette :
- l. 1. On demande à SPIP de :
- Ne pas insérer de boutons d’administration.
- Dire au navigateur que la page retournée est du json, et fournir le charset.
- l. 2 et l .15, les crochets servent à indiquer que nous retournons plusieurs objets JSON, chacun correspondant à un évènements.
- l. 2 nous bouclons sur les évènements. Entre chaque élèment de la boucle, nous affichons une virgule (
{", "}
). Nous trions par date de début : ceci servira plus loin lors de l’affichage des données sans Javascript. - l. 3-5 pour sélectionner les évènements, nous utilisons le critère
agendafull
. Les options de ce critère nous indique :-
date_debut
: que le champdate_debut
servira pour repérer … date de début de sélection. -
date_fin
: que le champdate_fin
servira pour repérer … date de fin de sélection. -
periode
que la période sélectionné sera déterminée par les options suivantes. -
#VAL{Y}|date{#ENV{start}}, #VAL{m}|date{#ENV{start}}, #VAL{d}|date{#ENV{start}}
que le début de la période correspond à la date passée dans#ENV{start}
. La syntaxe un peu absconse que vous voyiez issu permet d’extraire, respectivement, l’année, le mois et la jour depuis un timestamp. -
#VAL{Y}|date{#ENV{end}}, #VAL{m}|date{#ENV{end}}, #VAL{d}|date{#ENV{end}}</cpde> que la fin de la période correspond à la date passée dans <code>#ENV{end}
.
-
- l. 7-14 : nous remplissons un tableau SPIP via
#ARRAY
, puis nous le transformons en objet JSON, via le filtre||json_encode
. Ce tableau comprend les entrées suivantes :-
id
: identifiant unique pour FullCalendar. Ca tombe bien, SPIP attribut un identifiant à chaque évenement :#ID_EVENEMENT
-
title
: le titre. On transforme les entité HTML en caractère unicode (|html2unicode
) puis on s’assure de proposer des données avec le bon charset (|unicode2charset
). -
allDay
: on précise si l’évènement dure toute la journée. Utilisée pour l’affichage par jour. Pour préciser cela, on s’appuie sur le champ#HORAIRE
qui contient justement cette information. On utilise#EVAL
pour indiquer qu’on insére une valeur booléenne et non pas textuelle. -
start
: date de début. On garde le format SQL. -
end
: date de fin. On garde le format SQL. -
url
: lien. Pour le coup, on renvoie vers l’article. -
description
: description de l’évènement. Là encore, on converti en Unicode, puis dans le charset correct.
-
À noter que l’on pourrait définir d’autres données pour chaque évènement : on se refera à la documentation de l’objet Event de FullCalendar. Par exemple, on pourrait indiquer des classe HTML en fonction de la rubrique.
Il vous faut également créer un fichier agenda.json_fonctions.php
contenant les lignes suivantes :
<?php
include_spip('inc/json');
?>
Ceci assurera que le filtre json_encode
est bien chargé [1].
Et pour les personnes sans Javascript ?
Et oui, tout le monde n’a pas de Javascript. Comment on fait alors ? La solution consiste à afficher un calendrier sous forme de liste dans un div
dont l’id est calendrier-loading
. Si Javascript est activé, FullCalendar va masquer ce div
.
Comme on a déjà fabriqué une boucle dans le squelette agenda.json.html
, nous allons nous en reservir, afin d’éviter de dupliquer les critères. Pour ce faire, nous allons utiliser la boucle DATA de SPIP 3.
Nous mettons donc dans le squelette agenda.html
:
<B_agenda>
<div id="calendrier-loading">
<p class="pagination">#PAGINATION</p>
<BOUCLE_agenda(DATA){source json, #PRODUIRE{fond=agenda.json, start=0,end=2147483647,_=#REM|time}}{pagination 15}>
<dl>
[<dt><:agenda:evenement_titre:></dt>
<dd><a href="#VALEUR{url}">(#VALEUR{title})</a></dd>]
[<dt><:agenda:evenement_date:></dt>
<dd>(#VALEUR{start}|Agenda_affdate_debut_fin{#VALEUR{end},#VALEUR{allDay}|=={true}|?{non,oui}})</dd>]
[<dt><:agenda:evenement_descriptif:></dt>
<dd>(#VALEUR{description})</dd>]
</dl>
</BOUCLE_agenda>
<p class="pagination">#PAGINATION</p>
</div>
</B_agenda>
- l. 1-3 : partie optionnelle avant de la boucle, avec la pagination éventuelle.
- l. 4 : code de la boucle. Nous bouclons sur des données (
(DATA)
) au format json ({source json
) extrait du fichier produit (#PRODUIRE
) par le squeletteagenda.json.html
avec la valeur destart
égale à 0, c’est à dire au 1 janvier 1970 à minuit, et la valeurend
égale à 2147483647, c’est à dire à la date maximale gérée par les ordinateurs actuel, le 19 janvier 2038, 3h14m7s [2]. Ainsi, nous sommes sûr de récuperer tout les évènements de l’agenda. L’option_=#REM|time
permet de s’assurer de ne pas avoir de cache, puisque nous passons comme argument le moment d’appel (|time
). Nous paginons de 15 en 15. - l. 5-14 : nous affichons les données pour chaque évènement, via
#VALEUR{donne}
. Ces données sont tirées du JSON. - l. 16 et suivante ; partie optionelle arrière de la boucle.
On obtient alors un agenda, certe sommaire, mais au moins existant sans Javascript :
Conclusion
Vous voilà maintenant prêt à avoir un agenda avec FullCalendar. Bien sûr, il y aurait beaucoup de chose à améliorer, cependant cet article aborde déjà beaucoup de notions :
- produire du JSON avec SPIP.
- le formatage de FullCalendar.
- les boucles DATA.
Discussions par date d’activité
65 discussions
Sur le site de test sur Wamp, cela affiche bien un agenda http://localhost/babel-1/spip.php?page=agenda :
Le problème, cela affiche le texte de l’évènement en dessous du calendrier.
Comme je ne suis pas très bon en SPIP, je vous envoie les deux pages insérées dans squelettes et une copie d’écran.
J’ai sûrement du cafouillé.
L’article est créé avec le mot clé agenda et avec Date de rédaction antérieure : 19 septembre 2012
Je vous joints une copie d’écran
François
heu, j’aurais besoin de vos boucle pour comprendre.
Bonsoir,
Voici les codes
agenda.html
agenda.json.html
en vous remerciant,
et le code js qui appelle le .json ? je pense que le problème vient de là.
Bonsoir,
Voici le code en fichier image.
Même avec les balises code, je n’arrive pas à envoyer le message après visualisation.
Il y a une astuce pour les codes trop grands ?
Je pensais qu’il n’étais pas nécessaire de vous le donner, puisque c’est le votre. Mais je me dis que si j’ai changé des paramètres dans les autres codes, alors ce ne fonctionne pas bien.
J’utilise SPIP depuis le début, mais plus fais de modification du code depuis le 1.8.
Je pense que vous aurez remarqué ma faible capacité pour le nouveau code de SPIP.
Répondre à ce message
Super, merci pour cette contribution
Répondre à ce message
Je suis effaré par ce plugin... J’ai programmé par le passé et je m’efforçais de rendre les choses accessibles. Et je signale quand même qu’à l’origine Spip était prévu pour des gens n’ayant que des connaissances basiques d’internet.
Je n’ai besoin que d’un agenda basique. Je n’ai pas envie de passer des plombes voire des journées à essayer de comprendre votre code Javascript. Peut-être est-il possible d’utiliser votre agenda sans faire compliqué, mais vous ne l’indiquez pas.
Excusez le coup de gueule, mais il m’est souvent arrivé de me lancer dans des explications compliquées, qui décourageaient le quidam...
1) je ne suis pas responsable de ce changement technique, je ne suis pas l’auteur du plugin agenda.
2) un agenda n’est jamais quelquechose de simple à programmer
3) il ne faut pas être effrayé par le fait que cela soit du JS. Le code JS est assez simple (juste un appel à une fonction) et tout le reste n’est que des boucles basiques de SPIP.
Il s’agit bien là de l’affichage d’un agenda. Si vous voulez simplement une liste d’évenement, rien de plus simple que d’utiliser des boucles évenements entremelés dans du HTML classique.
Répondre à ce message
Bonjour à tous,
Dans l’interface privée, le plugin Agenda pour SPIP 3.0.4 marche super.
Mais dès que j’essaye de visualiser en ligne, impossible :
Si je fais http://www.davduf.net/?page=agenda
Je suis ensuite tombé sur cette page d’explications. J’ai copié collé scrupuleusement les deux pages indiquées.
Elles sont ici :
agenda.html : http://www.davduf.net/?page=agenda
agenda.jason.html : http://www.davduf.net/?page=agenda.jason
Prenons l’exemple là.
http://www.davduf.net/bootcamp-a-l-inis-montreal
Cet événement est bien dans la partie privée, mais pas dans la partie publique.
Une idée ? Merci d’avance !
J’ai installé la mise à jour de Agenda 3.6.11
Répondre à ce message
Bonjour,
je ne réussis pas à afficher l’agenda. J’obtiens l’erreur « Aucun squelette agenda.html n’est disponible. »
Sur Spip 3.0.4, avec plugin agenda 3.6.11, j’ai ajouté dans mon dossier « squelettes » le dossier « lib » contenant les documents de FullCalendar. Comment puis-je appeler l’agenda ?
Merci pour votre aide ou un peu plus de renseignements sur l’installation du FullCalendar.
Richard
tout d’abord, vous n’avez pas besoin d’installer la lib FullCalendar, puisqu’elle est déjà livré avec SPIP : c’est ce que je dis lorsque j’écrit SPIP 3.0.x, en ayant conservé l’organiseur dans plugins-dist..
Effacer donc le dossier lib que vous avez mis dans squelette.
Ensuite s’il vous dit « Aucun squelette agenda.html n’est disponible. » ca veut dire qu’il faut que vous le créer. J’explique dans mon tutoriel qu’y mettre. Je vous mal quoi faire de plus.
Vous avez un site d’exemple ?
Je suis confus, j’avais glissé le document agenda.html dans le squelette d’un sous-domaine du domaine principal... J’air réparé mon erreur, et tout fonctionne à merveille.
Cependant, merci de la précision sur la lib FullCalendar.
Merci également de la réponse rapide et pour l’ensemble de cette excellente « contribution pédagogique » qui pallie à l’obsolescence des filtres memo.
ca arrive à tout le monde …
Répondre à ce message
Ajouter un commentaire
Avant de faire part d’un problème sur un plugin X, merci de lire ce qui suit :
Merci d’avance pour les personnes qui vous aideront !
Par ailleurs, n’oubliez pas que les contributeurs et contributrices ont une vie en dehors de SPIP.
Suivre les commentaires : |