ListeActions
Introduction
Cette page décrit et commente un projet, initialement proposé par
JeremieCook, pour ajouter une nouvelle action à
WikiNi.
Cette nouvelle action, si elle est adoptée par l'équipe de développement, sera intégrée dans une future version de
WikiNi.
D'ici là, ce travail constitue une
ContributionsAvancees.
Fonctionnement
L'action {{tableofcontent}} crée un sommaire automatique de la page en cours.
Tous les titres de la page (== à =====) sont scannés et un sommaire est généré. Pour de longues pages, c'est très pratique. Des liens automatiques vers les titres (à l'aide d'une ancre) permettent d'accéder rapidement à toutes les sous rubriques.
Les modifications à apporter sont assez complexes mais ne pose aucun problème particulier. Si personne n'y voit d'inconvénient, je l'ajouterai à la version CVS quand j'en aurai la possibilité.
Toutes les suggestions sont les bienvenues. Les discussions peuvent prendre place sur la page
ActionSommaireDiscussion.
Commentaires
C'est un vieux sujet que ta proposition : cf.
AncresAutomatiquesPourLesTitres. Mais ton approche est plus pragmatique : les ancres ne servent qu'au sommaire à et à rien d'autre ce qui évite de se poser des questions métaphysiques sur l'usage des ancres ;) C'est toujours mieux que rien du tout... Une dernière question cependant, que je pose à tout le monde : idéalement, une page wiki devrait être très courte et les wikistes expérimentés conseillent la séparation en plusieurs pages lorsqu'une page prend de l'embonpoint (rendant donc tout sommaire inutile). Qu'avez-vous expérimenté ? Il vrai que sur wikini.net par exemple, il y a certaines pages assez longues... Pour l'intégration dans
WikiNi je ne suis pas contre, la modification étant peu impactante, mais je préfèrerai avoir d'autres avis là-dessus et un petit délai de réflexion. --
CharlesNepote
Puisqu'un avis est demandé ;-) voici le mien. Les pages courtes c'est très bien mais ce n'est pas une obligation. J'utilise wikini pour rédiger des tutos (sur excel). Si pour avoir le cours complet il faut se cogner 12 pages différentes et les imprimer séparément ce n'est pas plus pratique que de faire une page un peu plus longue avec un sommaire. C'est comme en tout, une question de mesure... --
MisAnge
- En creant une page Sommaire avec génération des actions Toc trail, et qui proposerait une action InclureTouT? ou ImprimeTouT? on aurait la pratique dont MisAnage? peut avoir besoin, non ? -- JdX
C'est possible de créer des ancres qui possèdent le nom du titre. Je me suis inspiré, pour les numéros, de
Dokuwiki. Pour éviter les problèmes de titres identiques (qui m'a fait renoncer à mettre le titre en toutes lettres), il suffit de le mettre sous la forme 1_Le_Titre, 2_La_Presentation etc. Si ça semble nécessaire je peux le faire. J'aimerais bien avoir d'autres avis également :) --
JeremieCook
Bugs
Testé dans non nombreux cas, sans problème.
En cas d'erreur, prévenez moi que je corrige l'algorithme.
Le traitement avec les expressions régulières est très pénible. Penser à tous les de figure me semble assez illusoire (pour le nettoyage du code)
14/05/2005 --
JmPhilippe
Lorsqu'on pré-visualise une page, ce sont les titres de la page non modifiée qui apparaissent dans la page pré-visualisée. J'imagine qu'on peut récupérer le texte de la page modifiée, mais comment ????
02/06/2005 --
JmPhilippe
L'action ramasse aussi les titres qui sont dans des parties de code encadrées de %%. Là où ça devient vraiment gênant, c'est qu'il y a un nombre non négligeable de langages pour lesquels le signe == est utilisé pour les conditions... Je n'ai pas testé mais j'imagine qu'il y a le même genre de problème dans les parties de texte Html encadrées de "".
28/09/2005 --
AndreVignaud
Les titres de niveau 1 (======) sont pris en compte comme des titre de niveau 2 (cf. mes remarques en bas de page).
- Tu parles des remarques tout en bas ? En fait je viens de regarder et cela est tout à fait logique puisque:
- maximum 5 "=" peuvent être capturés
- l'éventuel 6e serait repris par le $nonEgEg puisque l'expression "([^=]*=?[^=]+)*" correspond à
- 0 ou plus de carractères différents de =
- éventuellement le carractère =
- 1 ou plus de carractères différents de =
- par conséquent toute chaine commençant par un "=" suivi de plus d'un carractère différent de "=" (ou plus) est capturée par $nonEgEg. Comme il y a un $nonEgEg après chaque suite de carractères "=" dans la regexp complète, le dernier peut toujours tomber dedans
- pour corriger ce problème il faudrait modifier $nonEgEg comme suit: "([^=]+=)*[^=]+"
28/09/2005 --
LordFarquaad
- as tu essayé la regex que tu proposes ? Elle ne semble pas fonctionner... Tu peux faire un test des regexp avec un outils comme Kodos (http://kodos.sourceforge.net/) 29/09/2005 -- AndreVignaud
- non, effectivement je n'avais pas vérifié vu qu'elle est assez simple. Mais je viens d'installer kodos et elle semble très bien fonctionner, je te propose donc la regexp en version améliorée:
- /(?:[^=]+=)*[^=]+((?:=){2,6})((?:[^=]+=)*[^=]+)\1(?:[^=]+=)*[^=]+/
- Cette regexp (peut-être un peu plus complexe) sera beaucoup plus performante et se trompera moins souvent:
- la référence arrière \1 s'assure que le nombre d'= à droite est le même que celui de gauche
- elle ne capture que le nécessaire:
- les "="
- le titre
- Le "replace" doit donc être modifié comme suit (sauf erreur de ma part): '\1#NumTitre#\2\1 '
- Note qu'à mon avis il serait nettement préférable d'utiliser preg_match_all, ce qui permettre de ne capturer que les titres et non de tout capturer et remplacer de sorte qu'il ne reste que les titres... (ce qui pose problème en cas d'erreur de syntaxe ou de présence de code source) La regexp suivante serait alors suffisante: (?:^|[^=])((?:=){2,6})((?:[^=]+=)*[^=]+)\1(?:$|[^=]) et un traitement en php permettrait d'adapter bien mieux le menu. -- LordFarquaad
Modifications à apporter
Dans formatters/wakka.php
Tout d'abord, une modification du fichier formatter de base. Pour ajouter les "ancres" qui permettront de faire un lien direct depuis le sommaire.
Le code était illisible, compliqué et fatiguant à comprendre parfaitement. J'ai commenté et éclairci les parties qui m'intéressaient. C'est un peu plus long, mais beaucoup plus facile à comprendre et modifier par la suite.
Il est même certainement possible de regrouper en un seul test les 5 types de header. Je m'en occuperai à l'occasion
1ere partie
Declaration de la variable statique numTitre vers le haut du fichier :
- function wakka2callback($things)
- {
- static $oldIndentLevel = 0;
- static $oldIndentLength= 0;
- static $indentClosers = array();
- static $newIndentSpace= array();
- static $br = 1;
- static $numTitre = 0; // <= Ajout de cette ligne
2ème partie
Le code de base :
// header level 5
else if ($thing == "==")
{
static $l5 = 0;
$br = 0;
return (++$l5 % 2 ? "<h5>" : "</h5>");
}
// header level 4
else if ($thing == "===")
{
static $l4 = 0;
$br = 0;
return (++$l4 % 2 ? "<h4>" : "</h4>");
}
// header level 3
else if ($thing == "====")
{
static $l3 = 0;
$br = 0;
return (++$l3 % 2 ? "<h3>" : "</h3>");
}
// header level 2
else if ($thing == "=====")
{
static $l2 = 0;
$br = 0;
return (++$l2 % 2 ? "<h2>" : "</h2>");
}
// header level 1
else if ($thing == "======")
{
static $l1 = 0;
$br = 0;
return (++$l1 % 2 ? "<h1>" : "</h1>");
}
à remplacer en :
// header level 5
else if ($thing == "==")
{
static $l5 = 0;
$br = 0;
// Nouvelle occurence
++$l5;
// Ouverture d'une balise de titre
if ($l5 % 2)
{
++$numTitre;
return "<h5><a name=\"$numTitre\">";
}
// Fermeture du titre precedent
else
{
return "</a></h5>\n";
}
}
// header level 4
else if ($thing == "===")
{
static $l4 = 0;
$br = 0;
// Nouvelle occurence
++$l4;
// Ouverture d'une balise de titre
if ($l4 % 2)
{
++$numTitre;
return "<h4><a name=\"$numTitre\">";
}
// Fermeture du titre precedent
else
{
return "</a></h4>\n";
}
}
// header level 3
else if ($thing == "====")
{
static $l3 = 0;
$br = 0;
// Nouvelle occurence
++$l3;
// Ouverture d'une balise de titre
if ($l3 % 2)
{
++$numTitre;
return "<h3><a name=\"$numTitre\">";
}
// Fermeture du titre precedent
else
{
return "</a></h3>\n";
}
}
// header level 2
else if ($thing == "=====")
{
static $l2 = 0;
$br = 0;
// Nouvelle occurence
++$l2;
// Ouverture d'une balise de titre
if ($l2 % 2)
{
++$numTitre;
return "<h2><a name=\"$numTitre\">";
}
// Fermeture du titre precedent
else
{
return "</a></h2>\n";
}
}
// header level 1
else if ($thing == "======")
{
static $l1 = 0;
$br = 0;
// Nouvelle occurence
++$l1;
// Ouverture d'une balise de titre
if ($l1 % 2)
{
++$numTitre;
return "<h1><a name=\"$numTitre\">";
}
// Fermeture du titre precedent
else
{
return "</a></h1>\n";
}
}
--
JeremieCook
Note : l'attribut "name" disparaît de la norme XHTML 1.1. Il serait peut-être plus judicieux d'utiliser "id" ? --
CharlesNepote
Dans actions/tableofcontent.php
Dans le répertoire actions, créer le fichier tableofcontent.php
en voila le contenu :
<?php
/*
toc.php : Affiche le sommaire de la page en cours
Copyright 2003 Jeremie COOK
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
// Fonction de creation de sommaire
function creerSommaire ($tokens)
{
$token = $tokens[1];
static $numTitre = 0;
return "<li>$token</li>";
}
// Recuperation du contenu de la page
$page = $this->LoadPage($this->getPageTag());
$toc = $page["body"];
// Mise en forme du sommaire
$toc = str_replace("\r", "", $toc);
$toc = chop($toc)."\n";
// Nettoyage des donnees (on ne garde que les titres)
$nonEgEg = "([^=]*=?[^=]+)*"; // Suite de caractères sans ==
$toc = preg_replace("($nonEgEg((=){2,5})$nonEgEg((=){2,5})$nonEgEg)ms", "\\2#NumTitre#\\4\\2 ", $toc);
// Ajout des liens (dans l'ordre)
$toc = preg_replace_callback("(#NumTitre#)ms",
create_function (
'$matches',
'static $numTitre = 0; return "#".++$numTitre."#";'
)
, $toc);
// Remplacement des balises
$toc = preg_replace("((=){6}#(([0-9]+))#($nonEgEg)(=){6} )", "<li><h1><a href=\"#\\3\">\\4</h1></a></li>\n", $toc);
$toc = preg_replace("((=){5}#(([0-9]+))#($nonEgEg)(=){5} )", "<li><h2><a href=\"#\\3\">\\4</h2></a></li>\n", $toc);
$toc = preg_replace("((=){4}#(([0-9]+))#($nonEgEg)(=){4} )", "<li><h3><a href=\"#\\3\">\\4</h3></a></li>\n", $toc);
$toc = preg_replace("((=){3}#(([0-9]+))#($nonEgEg)(=){3} )", "<li><h4><a href=\"#\\3\">\\4</h4></a></li>\n", $toc);
$toc = preg_replace("((=){2}#(([0-9]+))#($nonEgEg)(=){2} )", "<li><h5><a href=\"#\\3\">\\4</h5></a></li>\n", $toc);
$toc = preg_replace("/<br \/>$/","", trim($toc));
// Affichage
echo '<div id="sommaire">';
echo '<h2>Sommaire</h2>'."\n";
echo '<ul>'."\n";
echo $toc;
echo "\n".'</ul>'."\n";
echo '</div>';
?>
Dans la feuille de styles CSS
Reste à mettre quelques styles dans le CSS pour un format un peu plus présentable.
Commentaires et contributions
Je viens d'implémenter ces modifications. J'ai fait quelques modif dans le CSS pour obtenir un affichage "sympa". Seul problème, les ancres sont toutes nommées "1" !!! Je ne comprend pas ? --
JeanMorlet
Je viens d'ajouter dans cette page (1ere partie) la déclaration de la variable statique numTitre que j'avais oubliée dans le code à modifier. Une simple ligne parmi les déclarations et le problème doit être résolu. Pardon pour la confusion. --
JeremieCook
Bonjour,
Je viens d'installer en local cette fonction et j'ai le lien ancre qui reste bloqué à "#1". De plus, la page ne s'affiche pas sous IE alors qu'elle s'affiche sous Firefox mais avec "#1" à chaque titre. J'ai recommencé les modifs deux fois. Une idée ?
Michel
Bonjour, n'est-ce pas le même problème que ci dessus ? As tu correctement ajouté la déclaration static $numTitre = 0; // <= Ajout de cette ligne ?
Merci pour cette contribution mais j'ai le même problème pour la numérotation des ancres. Elles restent toutes à "#1". Je pense avoir bien déclaré et édité les fichiers indiqués. Quelques idées ? -- SylvainBaillet.
Je trouve cette fonction intéressante, pourquoi ne pas l'intégrer dans la prochaine version ?
12/05/2005
Très pratique cette action mais je lui trouve quelques imperfections. J'en ai donc fait une variante disponible à la page
ActionSommaireDiscussion afin de résoudre les problèmes suivants :
- l'ancre <a name="..."></a> encadre le texte du titre dans le corps de la page, ce qui fait que le style du tag A joue sur le rendu des titres de la page lorsqu'on utilise l'action dans la page (et ce n'est bien sûr pas le cas sinon)
- les listes de liens créées pour générer le sommaire utilisent des tags H1, H2, etc., ce qui génère un sommaire assez encombrant vu la taille des titres, de plus si on change le style des titres, ça change aussi le style du sommaire...
- si le titre contient des caractères de formatage, ils ne sont pas transformés en code Html (par ex. //Titre// reste tel quel au lieu de devenir Titre)
- encore plus d'esthétisme dans le code Html généré !
On trouvera sur la page
ActionSommaireDiscussion le Php modifié ainsi que le CSS qui va bien. En espérant que ça serve...
--
JmPhilippe
27/09/2005
C'est la fonction que je cherchai à implémenté dans mon wiki...
Toutefois aprés l'avoir ajoutée à mon wiki, j'ai 3 remarques sur le code PHP :
- dans wakka.php ne pourrait-on pas écrire :
- return (++$l5 % 2 ? '<h5><a name="' . (++$numTitre) . '">' : '</a></h5>');
- au lieu de :
- ++$l5;
- Ouverture d'une balise de titre
- if ($l5 % 2)
- {
- ++$numTitre;
- return "<h5><a name=\"$numTitre\">";
- }
- Fermeture du titre precedent
- else
- {
- }
- normalement oui -- LordFarquaad
- dans l'action tableofcontent je ne vois pas l'utilité de la fonction creerSommaire
- toujours dans l'action ne faut-il pas remplacer :
- $toc = preg_replace("($nonEgEg((=){2,5})$nonEgEg((=){2,5})$nonEgEg)ms", "\\2#NumTitre?#\\4\\2 ", $toc);
- par
- $toc = preg_replace("($nonEgEg((=){2,6})$nonEgEg((=){2,6})$nonEgEg)ms", "\\2#NumTitre?#\\4\\2 ", $toc);
- je n'ai jamais essayé cette action mais effectivement ça parâitrait logique (mais que signifie ce $nonEgEg ? :-S). Par ailleurs cette regexp n'est pas du tout optimisée (trop de parenthèses...) et risque d'entrâiner beaucoup d'erreurs (pas le même nombre d'= de chaque côté du titre...) -- LordFarquaad
- L'expression régulière citée est extraite du code php de l'action (cf. ci-dessus) pour comprendre le rôle de $nonEgEg. -- AndreVignaud
- $nonEgEg est sensé rechercher toute chaîne ne contenant pas une suite d'au moins 2 signes = . A vrai, bien que pratiquant pas mal les expressions régulières, j'ai un peu du mal avec celle-là... -- JmPhilippe
09/01/2006
Pour ma part, je préfère ne pas avoir ces balises hX dans mon sommaire, pour qu'il reste léger graphiquement. A toutes fin utile, voici la portion de code a modifier pour avoir de simples liens dans une liste a puce. Les class .h1, .h2, etc permettent de modifier l'indentation.
// Remplacement des balises
$toc = preg_replace("((=){6}#(([0-9]+))#($nonEgEg)(=){6} )", "<li class=\"h1\"><a href=\"#\\3\">\\4</a></li>\n", $toc);
$toc = preg_replace("((=){5}#(([0-9]+))#($nonEgEg)(=){5} )", "<li class=\"h2\"><a href=\"#\\3\">\\4</a></li>\n", $toc);
$toc = preg_replace("((=){4}#(([0-9]+))#($nonEgEg)(=){4} )", "<li class=\"h3\"><a href=\"#\\3\">\\4</a></li>\n", $toc);
$toc = preg_replace("((=){3}#(([0-9]+))#($nonEgEg)(=){3} )", "<li class=\"h4\"><a href=\"#\\3\">\\4</a></li>\n", $toc);
$toc = preg_replace("((=){2}#(([0-9]+))#($nonEgEg)(=){2} )", "<li class=\"h5\"><a href=\"#\\3\">\\4</a></li>\n", $toc);
19/01/2006
Je viens d'essayer et avec quelques modifications trouvées dans la page de Discussion, ça marche très bien. Par contre j'ai des soucis quand un lien est dans un titre comme ici :
http://bookcrossing.apinc.org/wakka.php?wiki=FoireAuxQuestionsOfficielle
Je suis pour l'intégration de cette fonction dans les prochaines versions de
WikiNi à condition de corriger deux trois bugs (celui que je cite mais aussi l'intégration des formatage dans le sommaire.
BriCe
Je pense aussi que ça devrait faire partie du package de base, c'est pourquoi dans les
MaquettesStyleWikiniParDefaut il y a un sommaire affiché dans la page ! Malheureusement je crains de ne pas connaître suffisamment le moteur Wikini pour pouvoir aller plus loin dans le code de l'action. Il faudrait le soutien d'une personne plus compétente en la matière, notamment en Php ;-) . --
JmPhilippe
- Cela fait plusieurs demandes et propositions, qui trainent de manière récurrente dans les améliorations demandées : quelqu'un pourrait-il me dire ce qui bloque, car il semble que ce sujet n'ait plus bougé ? -- JdX
2006-08-22
Si je ne me trompe, cette action présente l'inconvéniant de ne pas bien fonctionner dans le cas où il y a des pages inclues (qui ne seront pas correctement prises en compte) ou s'il y a du code dans la page (le problème des
==). Je viens d'avoir une idée d'implémentation plus "poussée" mais qui devrait être fiable à 100%:
- en cours de rendu de la page, le formatteur wakka génère les encres pour les titres, et les sauve toutes quelque part (si on utilise la possibilité de GererLesActionsSousFormeDObjets, il pourrait transmettre directement cette information à l'ActionSommaire)
- lorsque l'ActionSommaire est appelée, elle fait deux choses:
- informer le formateur qu'il y a une demande d'affichage du sommaire
- "afficher" une balise spéciale, ne pouvant normalement figurer dans le texte (html) de sortie. Je pense que cette balise devrait faire l'affaire:
- après le formatage (attention aux appels récursifs du formateur !), deux cas sont possibles:
- l'ActionSommaire n'a pas été appelée
- l'ActionSommaire a été appelée
- le formateur remplace les occurences de la balise spéciale par le résultat d'un appel "spécial" (une méthode) de l'ActionSommaire
De cette magnière on peut être certain que tous les titres seront correctement affichés et qu'il n'y aura aucun problème d'ancres - puisque tous les titres doivent passer obligatoirement par le formateur, qui en informe directement l'
ActionSommaire.
Qu'en pensez-vous ?
--
LordFarquaad
- * vu ta remarque dans l'autre page TableDesMatieres je crois que je vais essayer de synthétiser tout ce que je trouverai sur le sujet, mais cela serait bien pratique d'avoir un RechercheTexte un peu plus sélectif.... (je n'ose dire "efficace et efficient" comme le forgeron ;-) -- JdX
Bonjour, rien de nouveau sur le sujet ????? --
JdX (implementation quelconque ??) --
JdX