Analyse d’un bug sur l’agenda

, par  Alain Laponche --- ---

Résumé

Le plugin Agenda version 3.18.4 (utilisé avec SPIP 3.1) prévoit lorsque l’on clique sur une date du minicalendrier, d’afficher

  • soit la page "jour.html" quand il y a plusieurs événéments associés à cette date ; cette page liste les événements, et pour chacun d’eux propose un lien vers la page article correspondante en fournissant en argument le numéro d’événement sous la forme : spip.php ?article7&id_evenement=2
  • soit - très logiquement -, quand il y a un seul événement pour cette date, directement la page de l’article.
    Problème : l’adresse générée est alors
    spip.php ?article7& amp ; id_evenement=2 (sans les espaces)
    (pour mémoire : Code ’& amp ;’ = caractère &
    Conséquence : la page article correspondante est bien affichée, mais ne mentionne pas l’événement.
    L’erreur provient du squelette "jour.html" qui fait une redirection quand plus d’un événement est détecté. Le nouveau lien est généré par la balise #URL_EVENEMENT.
    Il suffit de mettre un * derrière l’appel de cette balise pour régler le problème (plus de modification de & en ’& amp ;’.
    Donc corriger dans
    /plugins/auto/agenda/v3.18.4/squelettes/content/jour.html
    la ligne suivante
    [(#TOTAL_BOUCLE|>{1}|sinon_interdire_acces{#URL_EVENEMENT*})]

Problèmes

Quand on clique sur une date de l’agenda, on obtient l’article correspondant sans son événement (donc ni heure, ni lieu).
Idem quand on demande un article par la navigation : on ne voit pas qu’il y a des événements associés (sauf que l’Agenda ne présente plus que les dates où il y a un événement associé à cet article, mais pas évident à remarquer, sauf si le ou les événements sont dans le mois courant !).
En revanche, quand on passe par "tous les événements" de l’Agenda, le clic sur un événement fait bien apparaître l’article avec son événement.

Et le meilleur ! : quand on a 2 événements sur la même date, l’affichage est correct avec par exemple l’url : page=jour&date_debut=2017-08-23

De façon générale, ce serait bien qu’un article avec des événements les affiche de façon systématique ! Mais cela n’est pas possible tel quel, car il faudrait :
 soit transmettre en argument les numéros des événements
 soit les calculer au sein du squelette affichant l’article, à savoir
plugins/auto/sarkaspipr/v4.5.10/noisettes/article/description.html

Erreur d’appel

Le problème concerne donc le cas ou il n’y a qu’un événement pour une date.
Dans ce cas, l’absence de l’événement est du à une erreur sur l’appel de l’article :
http://www.orbi.infini.fr/spip.php?article7&id_evenement=1
Si on enlève "amp ;", on obtient bien l’affichage.
Il y a un "&" correct et un amp ; (code &) anormalement généré

Conclusion : quand plusieurs événéments associés à une date, ok (on obtient la liste des événements, chacun avec un lien vers leur article associé)
Mais quand un seul événement, on cherche à afficher directement l’article avec en argument le no de l’événement (malheureusement avec un "& amp ;"

Constat : l’erreur ne provient pas du Javascript, puisque l’erreur subsiste quand on le désactive. Mais hors Javascript, on voit que le lien généré par une date sur lequel il y a au moins un événement est de la forme http://www.orbi.infini.fr/spip.php?page=jour&date_debut=2017-08-23

C’est donc dans "jour.html" que tout se joue
Mais avant d’arriver à ce constat, j’ai analysé le fonctionnement du mini-calendrier. Même s’il n’est pas en cause, voici ci-dessous le résultat de mes constatations.

Analyse des squelettes associés à un article

Les composants d’une page "sarkaspipr" sont définis par
/orbi/plugins/auto/sarkaspipr/v4.5.10/body.html
Pour un article, il est appelé :
/orbi/plugins/auto/sarkaspipr/v4.5.10/content/article.html
qui appelle
/orbi/plugins/auto/sarkaspipr/v4.5.10/noisettes/article/description.html
Quand l’affichage d’un évenement est demandé sur un article, c’est le squelette suivant qui est alors appelé pour le présenter :
plugins/auto/agenda/v3.18.4/squelettes/inclure/resume/evenement.html

body.html appelle également (pour un article) le squelette "aside/article.html" (les noisettes en marge latérale).
Celui-ci appelle systématiquement
/orbi/plugins/auto/sarkaspipr/v4.5.10/aside/inc-plugins.html
qui appelle (enfin !) le squelette
plugins/auto/sarkaspipr/v4.5.10/noisettes/agenda/nav-minical.html

Appel du calendrier

Cette "noisette" agenda met le titre et assure l’affichage du calendrier avec la balise
#CALENDRIER_MINI
Appel :

<BOUCLE_ev(EVENEMENTS){id_evenement}>
#CALENDRIER_MINI{#DATE_DEBUT,date_debut,#URL_PAGE{jour},#URL_PAGE{calendrier_mini_event.json,id_article=#ID_ARTICLE}|parametre_url{id_mot,#ID_MOT}}
#SET{id_article,#ID_ARTICLE}
</BOUCLE_ev>
#CALENDRIER_MINI{#DATE_DEBUT,date_debut,#URL_PAGE{jour},#URL_PAGE{calendrier_mini_event.json}|parametre_url{id_article,#GET{id_article}}|parametre_url{id_rubrique,#GET{id_rubrique}}|parametre_url{id_mot,#ID_MOT}}
<//B_ev>

Si un événement est associé à la page article affichée, on passe dans la boucle, et on présente un calendrier mettant en surbrillance les seuls événements de cet article (fonctionnement ok)
Sinon, code alternatif, c’est la liste de tous les événements du mois.
Non, ce raisonnement est faux ; voir plus bas

Fonctionnement de la balise calendrier_mini

Il est expliqué dans https://contrib.spip.net/Calendrier-Mini-2-0

  • 1er argument : date courante ; le mini calendrier se positionnera sur le mois correspondant
  • 2ème argument : nom de la variable date passée en argument à la page appelée quand le visiteur clique sur un jour (ici, ce sera &date_debut=xxx)
  • 3ème argument : l’URL de la page sur laquelle envoyer le visiteur lorsqu’il clique sur un jour (#SELF par défaut) ; ici ce sera donc "page=jour&date_debut=xxx"
  • 4ème argument : l’URL appelée pour charger la liste en JSON des évènements entre deux dates (#URL_PAGEcalendrier_mini.json par défaut).

Cette balise est une fonction php décrite en
/orbi/plugins/auto/calendriermini/v2.4.1/balise/calendrier_mini.php

Affichage du calendrier

Le calendrier lui-même est affiché par
plugins/auto/calendriermini/v2.4.1/formulaires/calendrier_mini.html
grâce à une instruction au sein même de la balise.
Ce squelette prévoit une solution alternative en absence de Javascript : une liste de liens avec la date de l’événement
Sinon appel de la fonction Javascript qui elle-même appelle la fonction
orbi/plugins/auto/calendriermini/v2.4.1/javascript/calendrier_mini.js.html

La navigation d’un mois à un autre se fait immédiatement, sans rechargement de la page.
La liste des évènements pour le mois en cours est rechargée à chaque changement de mois en tâche de fond (chargement asynchrone au format JSON).
Ce squelette définit donc une variable "urljson". Il est constitué d’un tableau avec id_evenement et les principaux champs "évenement" (sans référence à un article). Son remplissage est assuré par
/orbi/plugins/auto/agenda/v3.18.4/squelettes/calendrier_mini_event.json.html

Code Javascript
Voici pour les navigateurs acceptant javascript, le code soumis :

<script type='text/javascript'>               /*<![CDATA[*/
if (window.jQuery)
        {jQuery(   function()
               {#SET{ui,#CHEMIN{javascript/ui/jquery-ui.min.js}
        }                                                [(#REM) SPIP 3.2+]
	[(#GET{ui}|oui)jQuery.getScript('#GET{ui}', function(){]jQuery.getScript('
        [(#PRODUIRE {fond=javascript/calendrier_mini.js,lang=#ENV{lang}}|compacte)]
        ',function(){minical.init('.minicalendar .calendar-container');}
                );
	[(#GET{ui}|oui)});]
        });}                                                        /*]]>*/
</script>

Les liens générés

L’url associé à chaque jour du mois a la forme basique
http://www.orbi.infini.fr/spip.php?page=jour&date_debut=’la date’
Cette page "jour" est définie par :
/orbi/plugins/auto/agenda/v3.18.4/squelettes/content/jour.html
Elle liste les événements du jour et pour chacun d’eux présente un résumé. Celui-ci est défini par :
/orbi/plugins/auto/agenda/v3.18.4/squelettes/inclure/resume/e ;venement.html
L’article associé à l’événement y est mentionné et un lien de type
http://www.orbi.infini.fr/spip.php?article22&id_evenement=34
permet d’accéder à la page présentant l’article et ses événements associés.

Là, le & est bon.
Le problème se pose donc seulement quand on part du calendrier affiché depuis une rubrique.


Analyse du 4 eme argument du calendrier

Il est constitué par le code suivant

#URL_PAGE{calendrier_mini_event.json}|parametre_url{id_article,#GET{id_article}}|parametre_url{id_rubrique,#GET{id_rubrique}}|parametre_url{id_mot,#ID_MOT}

Fonctionnement de la balise URL_PAGE
"#URL_PAGE retourne une URL de type « page publique », vers la page passée en paramètre et qui pourra être utilisée dans un lien.
Par exemple, pour accéder à la page générée par le squelette toto.html, située dans votre dossier "squelettes", #URL_PAGE{toto} généra automatiquement l’URL spip.php ?page=toto.
Un second paramètre est autorisé dans #url_page pour ajouter des paramètres à l’URL. Exemple #URL_PAGE{toto,id_article=#ID_ARTICLE} générera l’url "spip.php ?page=toto&id_article=XXX"

Le filtre "parametre_url{argument,xxx}" permet également de rajouter "&argument=xxx"
tandis que "parametre_url{argument}" supprime cet argument
En conséquence, le 4ème paramètre devient :
(url de calendrier_mini_event.json)
&id_article=xxx&id_rubrique=yyy&id_mot=zzz
Les arguments sans valeur n’apparaissent pas.
Ainsi l’argument d’identification de la page affichant le calendrier est transmis avec l’url contenant la liste des événements du mois visualisé ; on a donc autant de calendrier affichable que de combinaison "événement - article"
Mais quand plusieurs événements le même jour, correspondant donc à des articles différents, c’est bon ; et au contraire mauvais s’il n’y a qu’un seul événement
Où se situe ce traitement ?

Affichage de tous les événénements du mois quand il s’agit d’un article

Pour un article, la présentation du mini-calendrier se limite aux seuls événements concernant cet article. C’est peu parlant !
Il serait intéressant de présenter toujours le calendrier complet.
J’ai tenté d’adapter plugins/auto/sarkaspipr/v4.5.10/noisettes/agenda/nav-minical.html,
mais le problème est dans la génération de "calendrier_mini_event.json". Or cela se fait en amont. Où ?

Analyse documentation

Je pensais être en présence d’une erreur dans la balise #URL_PAGE"
D’autant que dans les supports, il est fait mention de ce remplacement de & dans la balise #url_page et dans le filtre |parametre_url

#url_page
Ainsi dans /orbi/ecrire/balise/url_.php
pour la balise url_page, on a les commentaires suivants

 * Compile la balise <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+I1VSTF9QQUdFPC9jb2RlPg=="></span> qui retourne une URL de type « page »
 *
 * - <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+I1VSTF9QQUdFe25vbX08L2NvZGU+"></span> génère l'url pour la page <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+bm9tPC9jb2RlPg=="></span>
 * - <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+I1VSTF9QQUdFe25vbSxwYXJhbT12YWxldXJ9PC9jb2RlPg=="></span> génère l'url pour la page <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+bm9tPC9jb2RlPg=="></span> avec des paramètres
 * - <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+I1VSTF9QQUdFPC9jb2RlPg=="></span> sans argument retourne l'URL courante.
 * - <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+I1VSTF9QQUdFKjwvY29kZT4="></span> retourne l'URL sans convertir les <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+JmFtcDs8L2NvZGU+"></span> en <span class="base64" title="PGNvZGUgY2xhc3M9InNwaXBfY29kZSBzcGlwX2NvZGVfaW5saW5lIiBkaXI9Imx0ciI+JmFtcDthbXA7PC9jb2RlPg=="></span>
 *
 * @balise
 * @link http://www.spip.net/4630
 * @see generer_url_public()
 * @example
 *     <div class="base64" title="PGRpdiBjbGFzcz0icHJlY29kZSI+PHByZSBjbGFzcz0ic3BpcF9jb2RlIHNwaXBfY29kZV9ibG9jayIgZGlyPSJsdHIiIHN0eWxlPSJ0ZXh0LWFsaWduOiBsZWZ0OyI+PGNvZGU+ICogICAgICNVUkxfUEFHRXtiYWNrZW5kfSBwcm9kdWl0ID9wYWdlPWJhY2tlbmQNCiAqICAgICAjVVJMX1BBR0V7YmFja2VuZCxpZF9ydWJyaXF1ZT0xfSBlc3Qgw6lxdWl2YWxlbnQgw6ANCiAqICAgICBbKCNVUkxfUEFHRXtiYWNrZW5kfXxwYXJhbWV0cmVfdXJse2lkX3J1YnJpcXVlLDF9KV0NCiAqICAgICA8L2NvZGU+PC9wcmU+PC9kaXY+"></div>
 *
 * @param Champ $p
 *     Pile au niveau de la balise
 * @return Champ
 *     Pile complétée par le code à générer
 

Il y est écrit que
#URL_PAGE* retourne l’URL sans convertir les & en &
La syntaxe serait [(#BALISE*arguments)]

|parametre_url
Autre piste avec le filtre "parametre_url" :
Par défaut, les URLs sont encodés avec le séparateur & mais il est possible de forcer le séparateur en indiquant un 3ème argument |parametre_urlnom de variable,valeur,separateur


Etude de la page=jour

Contient essentiellement

<BOUCLE_ev(EVENEMENTS){!evenement_passe #GET{date_debut}}{!evenement_a_venir #GET{date_fin}}{par date_debut}{id_article?}{id_rubrique?}{id_mot?}{id_evenement_source?}>
			[(#TOTAL_BOUCLE|>{1}|sinon_interdire_acces{#URL_EVENEMENT})]
					<li class="item">#INCLURE{fond=inclure/resume/evenement,id_evenement}</li>
				</BOUCLE_ev>
</boucle>

Les événements qui ne sont pas ...
" !evenement_passe #GETdate_debut"

[(#TOTAL_BOUCLE|>1|sinon_interdire_acces#URL_EVENEMENT)]
S’il y a plus d’un événement (#TOTAL_BOUCLE|>1)
le filtre |sinon_interdire_acces permet de rediriger vers une page d’erreur s’il est appliqué à une variable valant false
En l’occurence "#url_evenement". Cette balise est définie où ?
Dans un forum, il est dit que " #URL_EVENEMENT m’envoie sur l’article associé à l’événement et non sur l’événement lui même". C’est bien ce qui se passe dans mon cas ... et c’est donc bien là que se trouve mon bug !!!

Et en faisant une copie sous /squelettes et en mettant un * derrière la balise, c’est ok
D’où nouvelle version
/orbi/squelettes/content/jour.html

Autres analyses en vrac

Le lien généré associé à un jour serait en réalité du type
xxx ?page=jour&page_debut=jour cliqué
En parallele, le minicalendrier dispose d’une url donnant la liste des événements pour ce jour, completée par des &id_article. En conséquence, on dispose d’une url donnant la liste des événements propres à chaque article.
Conséquence, c’est la page "jour" qui serait remplacée sans qu’on est le temps de la voir.
Trouvé
orbi/plugins/auto/agenda/v3.18.4/squelettes/content/jour.html
Il y aurait en arguments, une date début (et de fin)
Celui crée une liste des événements à partir du squelette
inclure/resume/evenement.html
On voit que c’est le fonctionnement de la page "Agenda", mais prévue entre 2 dates
Donc nouvelle mauvaise piste ...
Pour info, le tableau json est défini par
orbi/plugins/auto/agenda/v3.18.4/squelettes/calendrier_mini_event.json.html

Tests réalisés

La modification du code de cette balise nécessiterait de se plonger dans
/orbi/ecrire/balise/url_.php
Mais la modif la plus simple est à faire dans une copie de
plugins/auto/sarkaspipr/v4.5.10/noisettes/agenda/nav-minical.html
c’est à dire dans
squelettes/noisettes/agenda/nav-minical.html
Ce que j’ai fait
A supprimer à terme, car :
1) : le filtre replace ne semble n’avoir aucun effet sur le résultat
2) : la mise en place de * derriere #URL_Page