Problème lié à l'utilisation d'un include pour gérer l'interface utilisateur
Nous avons évoqué plus haut la possibilité d'employer l'action
include pour laisser le contrôle de l'interface à l'utilisateur ; à ce titre, nous avons pris l'exemple du contrôle du menu de navigation grâce à un include : dans le fichier wakka.config.php, il suffit d'indiquer :
"navigation_links" => "{{include page=\"MenuDuHaut\"}}",
Cette possibilité a un effet de bord un peu génant : lorsque l'on affiche la page source, MenuDuHaut dans notre exemple, un message d'erreur est affiché en lieu et place du menu :
Impossible à une page de s'inclure dans elle même. Ce message est logique dans le cas d'un include d'une page dans corps même de sa propre page, mais il serait en revanche souhaitable que l'include fonctionne normalement lorsque l'include est réalisé en-dehors du corps de la page. (Suis-je clair ?)
Il existe une solution technique assez simple mais que je ne trouve pas très élégante : dans /handlers/page/show.php il suffit :
- de déclarer une variable juste avant le traitement du corps du texte et de la remettre à 0 après le traitement
- de tester la variable dans /actions/include.php
Dans /wakka.php :
var $page;
Dans /handlers/page/show.php :
// display page
- $this->in_page_body = true;
- echo $this->Format($this->page["body"], "wakka");
- $this->in_page_body = false;
Dans /actions/include.php :
if (strcasecmp($incPageName, $this->GetPageTag?()) and $this->in_page_body) {
- echo $this->Format("//Impossible à une page de s'inclure dans elle même.//");
NON !!!! Le test est faux, strcasecmp compare des chaine de caratères est renvoie une valeur >0 ou <0 ou =0 selon que la chaine1 est plus grande, plus petite ou égale à la chaine2. Hors ici, si les 2 chaine sont égale strcasecmp renvois 0 est donc le teste deviens faux...
Je préfère la version avec des expressions régulières, mais avec strcasecmp il faudrait plutôt écrire:
if (strcasecmp($incPageName, $this->GetPageTag?()==0) and $this->in_page_body) {
- echo $this->Format("//Impossible à une page de s'inclure dans elle même.//");
--
GarfieldFr
(non testé)
- Dis euh... tu n'as pas l'impression de te contredire là ? Dans ActionRedirect tu soutiens qu'il ne faut pas modifier le coeur pour que les plug-ins fonctionnent, et ici tu soutiens l'ajout d'une variable de classe et la modification d'un autre plug-in sans rapport direct :-S (à noter qu'il n'y aurait pas que le HandlerShow à modifier si on voulait faire cela...).
- Enfin bon, de toute façon ce problème sera résolu dès que j'aurai ajouté ce que j'ai proposé ci-dessous au cvs... (je sais, j'aurais dû le faire samedi mais j'ai oublié, et là il est trop tard, je le ferai ce soir...) -- LordFarquaad
- Non, je ne soutiens rien du tout, l'action redirect ne modifie par le coeur de WikiNi. Le code ci dessus n'est pas de moi, le code original ne demande pas de modification du coeur de WikiNi. Si par la suite quelqu'un a fait une modification qui amène un changement dans le coeur, je suis contre biensur. Mais de toute façon, je pense qu'il faudrait penser à réécrire depuis zéro WikiNi dans une version a venir pour passer en tout objet (action, handler...etc serait des objets).
Qu'en pensez-vous ? Voyez vous d'autres solutions ?
--
CharlesNepote
Je ne pense pas que ce soit utile de faire un test sur le fait que l'on soit dans le corp ou l'entête de la page simplement parce que la personne habilité à modifier le menu (ou toutes autre partie de l'interface) est l'administrateur du site et donc doit savoir ce qu'elle fait. Si la documentation de l'action indique que l'inclusion d'une page dans elle même est impossible, et bien le message d'erreur ne lui semblera pas anormal.
--
GarfieldFr
- La personne habilité à modifier le menu n'est pas forcément l'administrateur du site. Je suis actuellement en train de mettre en place en intranet un menu gauche où les utilisateurs veulent voir les actualités du site : les actualités du site est une page accessible à la totalité des utilisateurs ; chacun y publie ce qu'il veut, l'actualité est ainsi immédiatement publiée en page dans chaque menu de chaque page du wiki. Je peux vous citer beaucoup d'autres exemples où un élément de "menu" -- tout du moins un élément répetté sur chaque page -- peut avoir un intérêt à être modifié par tout utilisateur. Peut-être que le test que je propose n'est pas une bonne solution mais le problème ergonomique reste entier : le message "Impossible à une page de s'inclure dans elle même." pose problème aux utilisateurs. -- CharlesNepote
Oui, je confirme. l'utilisateur est roi.C'est la première des priorités :-) --
ThierryBazzanella.
Vers une personnalisation poussée de WikiNi ?
On peut aussi améliorer cette action en ajoutant la possibilité de styler le code produit à l'aide du paramètre "style" : ce dernier permet d'entrer du code CSS de façon équivalente à l'attribut HTML "style" : exemple :
{{include page="PagePrincipale" style="font-size: 9px;"}}
Cependant, il existe quelques problèmes de sécurité dus à l'attribut "style". J'ai posé la question dans la liste spécialisé CSS en français ; cf. le fil de discussion suivant :
http://fr.groups.yahoo.com/group/pompeurs/message/4085?threaded=1
Je vais voir comment il est possible d'intégrer l'attribut "style" en filtrant les propriétés CSS passées en paramètre.
--
CharlesNepote
Inclusion d'une page d'un autre WikiNi
Dans la page
WikiNiSyndication,
DavidDelon parle de recoder l'action
include pour faire de la syndication. J'ai codé une telle action include. Maintenant, le nom de la page est soit un URL soit une page
WikiNi local. Les syntaxe suivante sont donc valide :
- {{include page="http://www.wikini.net/wakka.php?wiki=ActionInclude"}}
- {{include page="ActionInclude"}}
Avec le changement de serveur arrive des problèmes de référence circulaire, cela est géré.
La seule chose qui ne soit pas gérée est le transfert des styles d'un serveur à l'autre, c'est à dire que si la page incluse provient d'un autre
WikiNi et que cette page inclus elle même une page avec un certain style, l'affichage pourra être différent.
J'ai déjà testé les références circulaires, mais pas de manière exhaustive. Je n'est pas vérifié si droit de lecture était correctement vérifié, à priori oui car la méthode /raw vérifie les droits de lecture.
Voici le code de l'action pour teste :
WikiNiSyndication
--
GarfieldFr
Trés bien cette action, le codage de l'ancienne syndication ne me plaisait pas vraiment. Je teste tout cela (éventuellement à partir de la branche CVS de Test si on se met d'accord dessus). --
DavidDelon
Tout ce que je fais de "distribuable à mon avis" se retrouve dans le CVS TEST pour que vous puissiez le tester. Donc la modification de include pour le support de page externe au site est dans le CVS TEST. --
GarfieldFr
NOTE
I have been trying to get the
ActionInclude to work on the latest (0.1.2) Wakkawiki code. I copied the include.php from the 0.4.1 tar ball and drop it on the /actions directory. I added var $parameter = array(); to the wakka class and added the function
GetParameter? as well. Still is not working, even though I am calling it {{include page="HomePage"}} it still says the parameter "page" is missing. Am I missing something? Thanks! --
DavidCollantes (
http://www.netbros.com/)
You did right in adding $parameter = array() and fonction
GetParameter?() in wakka.php, but you should also make these changes in wakka.php near line 330 :
// prepare an array for extract() to work with (in $this->IncludeBuffered())
if (is_array($matches))
{
for ($a = 0; $a < count($matches); $a++)
{
$vars[$matches[1][$a]] = $matches[2][$a];
$this->parameter[$matches[1][$a]]=$matches[2][$a];
}
}
}
if (!$forceLinkTracking) $this->StopLinkTracking();
$result = $this->IncludeBuffered(strtolower($action).".php", "<i>Unknown action \"$action\"</i>", $vars, $this->config["action_path"]);
$this->StartLinkTracking();
if (isset($parameter)) unset($this->parameter[$parameter]);
unset($this->parameter);
- Excellent!!! It works!!! Thanks!!!
Peut-on inclure une page d'un autre Wiki ?, d'un autre site ? --
FidelioEspoir
Non, cela est impossible. Il s'agit d'inclusion de page
WikiNi uniquement car la page incluse est soumise au formatage de Wikini et donc une page google ne peut pas être incluse. Par contre il doit etre possible d'ecrire une action du style {{includeURL URL="http://www.google.com/search?q=contrepeterie"}}. --
GarfieldFr
Par contre, avec quelques modifications, il doit être possible d'inclure une page d'un autre
WikiNi --
GarfieldFr
Idée superbe : tout ce qui permet de densifier les mailles du réseau enrichit
WikiNi --
FidelioEspoir
Include, page d'aide et MultiWikiNi
Ta fonction est parfaite pour insérer une page constamment actualisée. Lorsque je propose d'ouvrir une nouvelle fenêtre, c'est dans l'optique d'un changement de registre : Texte et Aide sur le texte , Web et meta-Web. L'avantage d'une nouvelle fenêtre permet de ne pas mélanger les deux historiques. On peut ainsi consulter plusieurs pages d'aide tout en restant sur la page étudiée. On peut surtout rester sur la Page Sujet tout en lisant les pages SujetAvisdeX , SujetAvisdeXY ou sur les pages "SujetHier , "SujetDemain . Cela permet en quelque sorte de quitter le Wiki, ensemble linéaire de liens à une dimension, pour un
MultiWikiNi. --
FidelioEspoir
Paramètre créant un bouton d'ouverture/fermeture du texte de l'include
Mais, pour te convaincre que je continue à adorer l'action "include", j'aimerais lui voir attacher une petite (!!??) action sous forme d'un bouton (!!???!!) : Fermer/ouvrir l'include. Clic et je lis le texte inséré, clic je le referme. Il suffit de (ah aha ah !) changer le style de l'include te dirait yakataka ! --
FidelioEspoir
Il faut voir : cf.
http://www.meyerweb.com/eric/css/edge/popups/demo.html. Je trouve le challenge assez amusant, mais je ne vois pas encore beaucoup d'applications (des idées ?). --
CharlesNepote
Ce site est superbe d'intelligence que... je n'ai pas. J'utilise le css pour seulement changer les couleurs de mon site. Utiliser les CSS au lieu d'un javascript est certainement l'avenir pour le développeur. Mais j'écris toujours ici en tant qu'utilisateur. L'avantage d'une seconde fenêtre est de permettre de continuer à écrire sur une page,
tout en continuant à lire l'autre. Mes remarques "informatiques" essayent de me faire mieux comprendre plus vite et surtout de vous convaincre que je partage vos difficultés de prog. Que tu y trouves aussi un plaisir, un amusant challenge me ravit au plus haut point !
En débutant mon site, j'avais mis à gauche une colonne menu permettant à chacun d'aller directement là où il le désire. (idée trouvée ici du côté de l'Afrique ;-) voir
ContributionsAvancees ) . Cette solution s'avère éminemment utile pour des sites où les pages se suivent à la queue leu leu. Mon site utilisant une pléthore de liens entre pages, elle s'avère finalement moins nécessaire et surtout elle prenait de la place dans chaque page. J'ai bien essayé de la faire disparaître avec le fameux bouton clic-clac, jour-nuit, en dédoublant mes wakka.css (bleu, jaune vert, marron...) avec leurs sosies où la table-column deviendrait width=0, où le texte serait invisible...J'ai abouti à un carnage : tout était sens dessus dessous, et les liens invisibles fonctionnaient toujours...Je l'ai donc abandonnée au profit d'un include en première page. A moins qu'un malicieux s'empare d'un bouton magique et s'y amuse... tant mieux pour tous !! ;-) --
FidelioEspoir
MenuDuHaut suite : création d'un menu personnalisé
Vous avez installé un menu "include". il est possible maintenant d'y ajouter une ligne "menupersonnel" :
Création d'une action menuutilisateur.php que l'on installe dans une page
MenuUtilisateur
<?php
/*...
licence GPL...
*/
if ($phrase = $_REQUEST["phrase"])
{
$phrase = trim($phrase);
$this->SetPersistentCookie("menu",$phrase,1);
$this->Redirect($this->href());
}
echo $this->FormOpen("", "", "get") ;
?>
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td>NomWiki uniquement </td>
<td><input name="phrase" size="40" value="<?php echo htmlentities($this->Getcookie("menu")) ?>" /> <input type="submit" value="Menu choisi" /></td>
</tr>
</table>
<?php echo $this->FormClose(); ?>
puis dans header.php
....<?php echo $this->config["navigation_links"] ? $this->Format($this->config["navigation_links"])." \n" : "" ?>
////
<br />
<a href="<?php echo $this->config["base_url"]?> menuduhaut" ">Menu</a> :
<?php
//pm
$menu = htmlentities($_COOKIE["menu"]);
$menu = explode(" ",$menu);
$menupersonel = "";
foreach ($menu as $nom){
$menupersonel = $menupersonel . $this->Link($nom)." ";
}
$menupersonel = rtrim($menupersonel);
if (!empty($menupersonel)) echo $menupersonel ;
?>
<br />
////
.....
et le menupersonel s'inscrit juste après le menuduhaut
Toute amélioration du script est fortement encouragée !
Chaque utillisateur enregistré ou non peut ainsi construire un menu contenant les cartes qu'il fréquente le plus. A l'usage, vous ne pourrez plus vous en passer ! 2004-05-22 -- 18 : 24 --
FidelioEspoir
Question: Pourquoi les images incluses dans une page pointée par un include ne sont pas visibles?
StephaneCvr
- Réponse: en principe elles devraient être visible, cela peut dépendre de la manière dont tu as inclus l'image. Par exemple, via l'action {{attach}} cela devrait effectivement planter(mais pas sur, je sais plus trop comment j'ai codé l'action include), mais si tu met l'url complète de l'image il ne devrait pas y avoir de problème. Aurais tu une page exemple ? --GarfieldFr
Suite au bug que j'avais signalé dans les
RapportsDeBogues, je propose le code suivant:
Dans la
ClasseWiki, ajout d'une variable
$inclusions, et ajout des méthodes suivantes:
<?php
// inclusions
/**
* Enrégistre une nouvelle inclusion dans la pile d'inclusions.
* @param string $pageTag Le nom de la page qui va être inclue
* @return int Le nombre d'éléments dans la pile
*/
function RegisterInclusion($pageTag){
return array_unshift($this->inclusions, strtolower(trim($pageTag)));
}
/**
* Retire le dernier élément de la pile d'inclusions.
* @return string Le nom de la page dont l'inclusion devrait se terminer.
* NULL s'il n'y a plus d'inclusion dans la pile.
*/
function UnregisterLastInclusion(){
return array_shift($this->inclusions);
}
/**
* Renvoie le nom de la page en cours d'inclusion.
* @example // dans le cas d'une action comme l'ActionEcrivezMoi
* if(strtolower($this->GetPageTag()) != $this->CurrentInclusion())
* echo 'Cette action ne peut être appelée depuis une page inclue';
* @return string Le nom (tag) de la page (en minuscules)
* FALSE si la pile est vide.
*/
function CurrentInclusion(){
return isset($this->inclusions[0]) ? $this->inclusions[0]: FALSE ;
}
/**
* Vérifie si on est à l'intérieur d'une inclusion par $pageTag (sans tenir compte de la casse)
* @param string $pageTag Le nom de la page à vérifier
* @return bool True si on est à l'intérieur d'une inclusion par $pageTag (false sinon)
*/
function IsIncludedBy($pageTag){
return in_array(strtolower($pageTag), $this->inclusions);
}
/**
* @return array La pile d'inclusions
* L'élément 0 sera la dernière inclusion, l'élément 1 sera son parent et ainsi de suiste.
*/
function GetAllInclusions(){
return $this->inclusions;
}
/**
* Remplace la pile des inclusions par une nouvelle pile (par défaut une pile vide)
* Permet de formatter une page sans tenir compte des inclusions précédentes.
* @param array La nouvelle pile d'inclusions.
* L'élément 0 doit représenter la dernière inclusion, l'élément 1 son parent et ainsi de suite.
* @return array L'ancienne pile d'inclusions, avec les noms des pages en minuscules.
*/
function SetInclusions($pile = array()){
$temp = $this->inclusions;
$this->inclusions = $pile;
return $temp;
}
?>
Nouvelle version de l'action include:
<?php
// récuperation du parametres
$incPageName = trim($this->GetParameter('page'));
/**
* @todo améliorer le traitement des classes css
*/
if ($this->GetParameter('class')) {
$array_classes = explode(' ', $this->GetParameter('class'));
$classes = '';
foreach ($array_classes as $c) {
if($c) $classes .= ($classes ? '':' ') . "include_$c";
}
}
// Affichage de la page ou d'un message d'erreur
if (empty($incPageName)) {
echo $this->Format('//Le paramètre "page" est manquant.//');
} elseif ($this->IsIncludedBy($incPageName)) {
$inclusions = $this->GetAllInclusions();
$pg = strtolower($incPageName); // on l'effectue avant le for sinon il sera recalculé à chaque pas
$err = '[[' . $pg . ']]';
for($i = 0; $inclusions[$i] != $pg; $i++) {
$err = '[[' . $inclusions[$i] . ']] @@->@@ ' . $err;
}
echo $this->Format("//Impossible pour la page '[[$incPageName]]' de s'inclure dans elle même//"
. ($i ? ":---**Chaine d'inclusions**: [[$pg]] @@->@@ $err": '.')); // si $i = 0, alors c'est une page qui s'inclut elle-même directement...
} elseif (!$this->HasAccess('read',$incPageName)) {
echo $this->Format("//Lecture de la page inclue '\"\"$incPageName\"\"' non autorisée.//");
} elseif(!$incPage = $this->LoadPage($incPageName)) {
echo $this->Format("//La page inclue '[[$incPageName]]' ne semble pas exister...//");
} else {
$this->RegisterInclusion($incPageName);
$output = $this->Format($incPage['body']);
if (isset($classes)) echo "<div class=\"$classes\">\n$output</div>\n";
else echo $output;
$this->UnregisterLastInclusion();
}
?>
(j'ai utilisé mon propre standard de programmation, vu que les
DiscussionsNormeDeCodagePHPPourWikiNi n'ont pas encore abouti...
Je sais que les @ c'est pour barrer du texte, mais cela donne particulièrement bien sur ces flèches, regardez:
-> lol à changer, mais bizarrement le gras ne donnait rien chez moi :s)
Il faut aussi modifier les handlers show, edit, slide_show (qui, je pense, devrait être réécrit pour ne plus qu'il formatte tout quand il n'a besoin que d'un morceau...) et diff pour qu'ils ajoutent la page en cours comme première inclusion, c'est assez simple. (si je ne me trompe ce sont actuellement les seuls handlers qui formattent des pages.
addcomment ne le fait actuellement pas, mais je trouve qu'il devrait... si vous voulez savoir pourquoi, posez la question dans
DevActionsEntetePiedDePageEtLinktracking).
Ce code corrige notemment le "bug" qui affichait un message d'erreur lorsque l'on éditait une page inclue dans l'entête.
J'attends votre avis mais je pense que ça devrait être bon pour le cvs.
[Ok en ce qui me concerne. -- ProgFou - Pas d'autres avis ? Dans ce cas je l'ajouterai au CVS demain soir -- LordFarquaad] J'ai fait plusieurs tests chez moi et ils me paraissent très concluants:
Cela affiche bien les messages d'erreur auxquels on s'attend, ainsi que la page ParametresUtilisateur dans les trois pages.
Je n'ai pas fait la modification que propose
GarfieldFr dans
WikiNiSyndication, car la trouve trop compliquée et restrictive (marche que avec les sites
WikiNi qui n'utilisent pas la
ReecritureDURL et n'ont changé aucun nom de fichier, paramètre etc.). L'avantage par rapport à
[[|url]] me parait donc trop négligeable... Je vais tout de même détailler ce qu'il serait possible de faire:
Pour moi le mieux serait d'ajouter à l'action include un paramètre from dans lequel il faudrait placer une url avec un %s pour répérer l'endroit où insérer les noms de page. Ca donnerait quelque chose de ce genre:
{{include page="MyPostit" from="http://knowledge.martignier.net/wakka.php?wakka=%s/raw"}}.
Le paramètre from pourrait à se moment là accepter tout simplement des références interwiki, en supposant qu'on peut ajouter /raw à tous ceux d'entre eux qui sont des
WikiNi (de toute façon on ne saurait pas faire grand chose des autres à part en cherchant les
<body...>...</body>... je pense que c'est creusable mais pas pour les intewiki. Ca pourrait être fait en spécifiant une url dans le "page" sans spécifier de from... d'ailleurs ce serait une inclusion bien plus simple et universelle [sauf pour les liens relatifs... -> trop complexe à envisager])
On pourrait aussi envisager un troisième paramètre pour spécifier s'il faut faire les éventuelles inclusions avec des pages locales ou distantes.
Pour éviter les références circulaires, il faudrait, je pense, envisager une pile secondaire (statique) dans l'action include. La méthode
RegisterInclusion() pourrait très bien être utilisée pour enrégistrer les urls reconstituées (ex.:
http://knowledge.martignier.net/wakka.php?wakka=MyPostit/raw. Le seul problème que cela pourrait poser c'est le cas où deux sites dont les urls ne diffèrent que par leur casse possède des pages du même nom... ça va chercher loin :-j), tandis que la pile statique de l'action include servirait à enrégistrer uniquement les from (et éventuellement la valeur du troisième paramètre) à partir du moment où il y a de la syndication. Il y a juste une chose qui peut poser problème c'est que cette pile statique serait accessible à n'importe quelle action, mais ce n'est pas pire qu'une pile globale...
--
LordFarquaad