Wikini

NePasChargerHeaderEnPremier

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-3-94-99-173.compute-1.amazonaws.com
Cette page avait pour objectif de décrire les avantages que WikiNi gagnerait à ne pas charger l'entête en premier (comportement de la plupart des handlers) et à proposer une solution technique (ou du moins un exemple de mise en oeuvre).

Depuis le 02/10/2006 les changements proposés ont été intégrés au CVS HEAD, avec la solution b. comme point de départ de la mise en oeuvre. Cela a été intégré en raison notemment en raison des besoins de la RoadMapNouveauStyleWikiNi.

Fonctionnement actuel de WikiNi

Description du fonctionnement actuel de WikiNi concernant le chargement et l'affichage des différents éléments d'une page par la plupart des handlers (sauf le HandlerEdit? dans la version cvs suite à une de mes modifications):
  1. chargement de l'entête (ActionHeader?)
  2. affichage de l'entête
  3. chargement et traitement de la page
  4. affichage de la page traitée
  5. chargement du pied de page (ActionFooter?)
  6. affichage du pied de page

avantages


inconvénients


Correction des inconvénients

Pour corriger les inconvénients, il faut changer l'ordre de traitement des éléments qui composent la page comme ceci:
  1. chargement et traitement de la page
  2. chargement de l'entête (ActionHeader?)
  3. affichage de l'entête
  4. affichage de la page traitée
  5. chargement du pied de page (ActionFooter?)
  6. affichage du pied de page

Ceci résoud les inconvéniants


Mise en oeuvre de la solution

Pour implémenter cette technique, il faut modifier chaque handler. Il existe deux solutions pour ce faire:
  1. Utiliser une mise en cache dans une variable: c'est ce qui se fait dans le HandlerEdit? (WikiNi >= 0.5.0):
    • on définit une variable $buffer initialisée à la chaine vide ''
    • on remplace chaque appel de echo par $buffer .=
    • on remplace l'affichage de html brut (c'est à dire le html en dehors des balises php) par des chaines de caractères équivalentes que l'on concate de la même façon à $buffer
      • à noter qu'il est certainement plus simple d'utiliser des guillemets simples pour ce faire vu que le html contient déjà des guillemets doubles
  2. Utiliser la mise en cache fournie par php, c'est à dire les fonctions ob (déjà utilisées massivement dans WikiNi, notemment dans la méthode IncludeBuffered)
    • on remplace l'appel du header par ob_start();
    • juste avant l'apel du footer, on ajoute:
      • $buffer = ob_get_clean();
      • echo $this->Header();
      • echo $buffer;
La deuxième technique est beaucoup plus simple puisqu'elle ne nécessite que très peu de modification des handlers. Par exemple si on l'applique au HandlerShow, ça donne ceci:
<?php
/*
$Id: show.php,v 1.19 2005/03/07 22:40:09 nepote Exp $
Copyright (c) 2002, Hendrik Mans <hendrik@mans.de>
Copyright 2002, 2003 David DELON
Copyright 2002, 2003 Charles NEPOTE
Copyright 2003  Eric DELORD
Copyright 2003  Eric FELDSTEIN
Copyright 2004  Jean Christophe ANDRÉ
Copyright 2005-2006  Didier Loiseau
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

// Vérification de sécurité
if (!defined("WIKINI_VERSION"))
{
    die (
"acc&egrave;s direct interdit");
}

ob_start();
?>
<div class="page">
<?php
if ($HasAccessRead=$this->HasAccess("read"))
{
    if (!
$this->page)
    {
        echo 
"Cette page n'existe pas encore, voulez vous la <a href=\"".$this->href("edit")."\">cr&eacute;er</a> ?" ;
    }
    else
    {
        
// comment header?
        
if ($this->page["comment_on"])
        {
            echo 
"<div class=\"commentinfo\">Ceci est un commentaire sur ",$this->ComposeLinkToPage($this->page["comment_on"], """"0),", post&eacute; par ",$this->Format($this->page["user"])," &agrave; ",$this->page["time"],"</div>";
        }

        if (
$this->page["latest"] == "N")
        {
            echo 
"<div class=\"revisioninfo\">Ceci est une version archiv&eacute;e de <a href=\"",$this->href(),"\">",$this->GetPageTag(),"</a> &agrave; ",$this->page["time"],".</div>";
        }


        
// display page
        
$this->RegisterInclusion($this->GetPageTag());
        echo 
$this->Format($this->page["body"], "wakka");
        
$this->UnregisterLastInclusion();

        
// if this is an old revision, display some buttons
        
if (($this->page["latest"] == "N") && $this->HasAccess("write"))
        {
            
$latest $this->LoadPage($this->tag);
            
?>
            <br />
            <?php echo  $this->FormOpen("edit"?>
            <input type="hidden" name="previous" value="<?php echo  $latest["id"?>" />
            <input type="hidden" name="body" value="<?php echo  htmlentities($this->page["body"]) ?>" />
            <input type="submit" value="R&eacute;&eacute;diter cette version archiv&eacute;e" />
            <?php echo  $this->FormClose(); ?>
            <?php
        
}
    }
}
else
{
    echo 
"<i>Vous n'&ecirc;tes pas autoris&eacute; &agrave; lire cette page</i>" ;
}
?>
<hr class="hr_clear" />
</div>


<?php
if ($HasAccessRead && (!$this->page || !$this->page["comment_on"]))
{
    
// load comments for this page
    
$comments $this->LoadComments($this->tag);
    
    
// store comments display in session
    
$tag $this->GetPageTag();
    if (!isset(
$_SESSION["show_comments"][$tag]))
        
$_SESSION["show_comments"][$tag] = ($this->UserWantsComments() ? "1" "0");
    if (isset(
$_REQUEST["show_comments"])){    
    switch(
$_REQUEST["show_comments"])
    {
    case 
"0":
        
$_SESSION["show_comments"][$tag] = 0;
        break;
    case 
"1":
        
$_SESSION["show_comments"][$tag] = 1;
        break;
    }
    }
    
// display comments!
    
if ($this->page && $_SESSION["show_comments"][$tag])
    {
        
// display comments header
        
?>
        <div class="commentsheader">
            Commentaires [<a href="<?php echo  $this->href("""""show_comments=0"?>">Cacher commentaires/formulaire</a>]
        </div>
        <?php
        
        
// display comments themselves
        
if ($comments)
        {
            foreach (
$comments as $comment)
            {
                echo 
"<a name=\"",$comment["tag"],"\"></a>\n" ;
                echo 
"<div class=\"comment\">\n" ;
                if (
$this->HasAccess('write'$comment['tag'])
                 || 
$this->UserIsOwner($comment['tag'])
                 || 
$this->UserIsAdmin($comment['tag']))
                {
                    echo 
'<div class="commenteditlink">';
                    if (
$this->HasAccess('write'$comment['tag']))
                    {
                        echo 
'<a href="',$this->href('edit',$comment['tag']),'">&Eacute;diter ce commentaire</a>';
                    }
                    if (
$this->UserIsOwner($comment['tag'])
                     || 
$this->UserIsAdmin($comment['tag']))
                    {
                        echo 
'<br />','<a href="',$this->href('deletepage',$comment['tag']),'">Supprimer ce commentaire</a>';
                    }
                    echo 
"</div>\n";
                }
                echo 
$this->Format($comment["body"]),"\n" ;
                echo 
"<div class=\"commentinfo\">\n-- ",$this->Format($comment["user"])," (".$comment["time"],")\n</div>\n" ;
                echo 
"</div>\n" ;
            }
        }
        
        
// display comment form
        
echo "<div class=\"commentform\">\n" ;
        if (
$this->HasAccess("comment"))
        {
            
?>
                Ajouter un commentaire &agrave; cette page:<br />
                <?php echo  $this->FormOpen("addcomment"); ?>
                    <textarea name="body" rows="6" cols="65" style="width: 100%"></textarea><br />
                    <input type="submit" value="Ajouter Commentaire" accesskey="s" />
                <?php echo  $this->FormClose(); ?>
            <?php
        
}
        echo 
"</div>\n" ;
    }
    else
    {
        
?>
        <div class="commentsheader">
        <?php
            
switch (count($comments))
            {
            case 
0:
                echo 
"Il n'y a pas de commentaire sur cette page." ;
                break;
            case 
1:
                echo 
"Il y a un commentaire sur cette page." ;
                break;
            default:
                echo 
"Il y a ",count($comments)," commentaires sur cette page." ;
            }
        
?>
        
        [<a href="<?php echo  $this->href("""""show_comments=1"?>">Afficher commentaires/formulaire</a>]

        </div>
        <?php
    
}
}
$content ob_get_clean();
echo 
$this->Header();
echo 
$content;
echo 
$this->Footer();
?>


Interaction avec l'entête (ActionHeader?)

Comme dit plus haut, cette technique permet d'interagir avec l'entête. La plupart de ces interactions résident probablement au niveau des actions utilisées dans la page, bien que cela laisse également au handler la possibilité d'interagir aussi. Une première interraction possible est celle qui permettrait de modifier le titre et les meta description et keywords de l'entête, pour une meilleure indexation dans les moteurs de recherche, et pour donner un titre plus clair à chaque page. Pour ce faire je vais baser mes modifications sur la possibilité de GererLesActionsSousFormeDObjets, ce qui simplifie grandement l'implémentation (mémoire propre de l'action, facilité de vérifier les arguments). Cette implémentation est extrêmement simple puisqu'il suffit d'adapter l'ActionHeader? elle-même pour l'appliquer. Je me base donc sur la version de l'ActionHeader? que j'avais fournie dans GererLesActionsSousFormeDObjets, voici ce que ça donne:
<?php
/* header.php
Copyright (c) 2002, Hendrik Mans <hendrik@mans.de>
Copyright 2002, 2003 David DELON
Copyright 2002, 2003, 2004 Charles NEPOTE
Copyright 2002  Patrick PAUL
Copyright 2003  Eric DELORD
Copyright 2006  Didier LOISEAU
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. The name of the author may not be used to endorse or promote products
derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

class ActionHeader extends WikiniAction {
    var 
$title;
    var 
$desc;
    var 
$keyw;
    
    function 
ActionHeader(&$wiki)
    {
        
parent::WikiniAction($wiki);
    }
    
    function 
PerformAction($argz)
    {
        
$err true;
        
$res '';
        if (isset(
$argz['title']))
        {
            
$err false;
            
$this->title $argz['title'];
            
$res .= $this->HtmlWarning('D&eacute;finition du titre: ' htmlspecialchars($this->title));
        }
        if (isset(
$argz['pagedesc']))
        {
            
$err false;
            
$this->desc $argz['pagedesc'];
            
$res .= $this->HtmlWarning('D&eacute;finition du meta description: ' htmlspecialchars($this->desc));
        }
        if (isset(
$argz['pagekeyw']))
        {
            
$err false;
            
$this->keyw $argz['pagekeyw'];
            
$res .= $this->HtmlWarning('D&eacute;finition du meta keywords: ' htmlspecialchars($this->keyw));
        }
        if(
$err)
        {
            return 
'L\'action header n&eacute;cessite au moins un argument parmis &quot;title&quot;, &quot;pagedesc&quot; ou &quot;pagekeyw&quot;<br />';
        }
        if (
$this->wiki->GetMethod() != 'show')
        {
            return 
$res;
        }
        return 
'';
    }
    
    function 
HtmlWarning($text)
    {
        return 
'<span style="color: red; font-weight: bold;">' $text '</span><br />';
    }
    
    function 
GenerateHeader()
    {
        
$wiki = &$this->wiki;
        
$message $wiki->GetMessage();
        
$user $wiki->GetUser();
        
ob_start();
?><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
<title><?php echo empty($this->title) ? $wiki->GetWakkaName().":".$wiki->GetPageTag() : htmlspecialchars($this->title); ?></title>
<?php if (($wiki->GetMethod() != 'show') or (isset($_REQUEST['phrase'])) or ($_REQUEST['show_comments'] == '0') or (isset($_REQUEST['time']))) echo "<meta name=\"robots\" content=\"noindex, nofollow\"/>\n";?> 
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"/>
<meta name="keywords" content="<?php echo empty($this->keyw) ? $wiki->GetConfigValue("meta_keywords") : htmlspecialchars($this->keyw); ?>" />
<meta name="description" content="<?php echo empty($this->desc) ? $wiki->GetConfigValue("meta_description") : htmlspecialchars($this->desc); ?>" />
<link rel="stylesheet" type="text/css" media="screen" href="wakka.basic.css" />
<style type="text/css" media="all"> @import "<?php echo (!isset($_COOKIE["sitestyle"]))?'wakka':$_COOKIE["sitestyle"?>.css";</style>
<script type="text/javascript">
function fKeyDown()    {
    if (event.keyCode == 9) {
        event.returnValue= false;
        document.selection.createRange().text = String.fromCharCode(9) } }
</script>
</head>


<body <?php echo (!$user || ($user["doubleclickedit"] == 'Y')) && ($wiki->GetMethod() == "show") ? "ondblclick=\"document.location='" addslashes($wiki->href("edit")) . "';\" " "" ?>
<?php 
echo $message "onLoad=\"alert('".$message."');\" " "" ?> >


<div style="display: none;"><a href="<?php echo $wiki->href() ?>/resetstyle" accesskey="7"></a></div>


<h1 class="wiki_name"><?php echo $wiki->config["wakka_name"?></h1>


<h1 class="page_name">
<a href="<?php echo $wiki->config["base_url"?>RechercheTexte&amp;phrase=<?php echo urlencode($wiki->GetPageTag()); ?>">
<?php echo empty($this->title) ? $wiki->GetPageTag() : htmlspecialchars($this->title); ?>
</a>
</h1>


<div class="header">
<?php echo $wiki->ComposeLinkToPage($wiki->config["root_page"]); ?> ::
<?php echo $wiki->config["navigation_links"] ? $wiki->Format($wiki->config["navigation_links"])." :: \n" "" ?>
Vous &ecirc;tes <?php echo $wiki->Format($wiki->GetUserName()); if ($user $wiki->GetUser()) echo " (<a href=\"".$wiki->config["base_url"] ."ParametresUtilisateur&amp;action=logout\">D&eacute;connexion</a>)\n"?>
</div>
<?
        return ob_get_clean();
    } // GenerateHeader
} // class ActionHeader
?>

Vous noterez que l'action mémorise donc à présent les paramètres titre, description et keywords lorsqu'elle est appelée dans la page, et les réutilise une fois qu'elle est affichée pour de bon. Lors de l'appel de l'action une variable $res stocke les changements qui ont été effectués, afin de les afficher si on est dans un autre mode que show (ça permet de voir le changement lors d'un diff par exemple). Ceci est assez facultatif mais ça me parait tout de même utile.

D'autres formes d'interactions sont également tout à fait envisageables, quelques idées me viennent à l'esprit:

Discussions

Qu'en pensez-vous ? -- LordFarquaad

Pour moi c'est une évolution absolument nécessaire car certaines actions ont ou pourraient avoir vocation à créer un code XHtml qui ne doit pas atterrir dans la zone de texte. En effet si on crée des groupes de pages, il vaut mieux sortir de la zone de texte le menu de ces pages pour le mettre plus en valeur. On pourrait aussi imaginer une action qui servirait à délimiter des sections dans le wiki. Le nom de la section serait alors extrait de la page pour être affiché de manière plus ostensible. Enfin la possibilité d'insérer ponctuellement une feuille de style (voire un javascript) permettrait d'avoir quelques pages plus raffinées sur le plan graphique ou interaction avec l'utilisateur, notamment la page d'accueil. -- JmPhilippe

D'autres idées me viennent à l'esprit. Le petit texte de la page d'accueil "Les développeurs de WikiNi vous invitent..." pourrait être géré par une action. Ceci permettrait d'afficher de petits messages bien visibles dans certaines pages. De même, on peut imaginer une action PageEnConstruction qui changerait par exemple les couleurs de la mise en page... J'ai donc l'impression que cela ouvrirait plein de possibilités. Pour les aspects techniques, je te fais confiance ! -- JmPhilippe

Je pense qu'il faut voir encore plus générique. Il faut toujours charger tout le contenu d'une page avant de commencer le tout premier affichage. C'est ce que font tous les CMS. Cette fonctionnalité permetterai de pouvoir séparer le traitement de l'affichage et donc créer des templates. Et des templates, c'est exactement ce dont on aura besoin pour l'i18n. -- JulienLanglois?


LordFarquaadASuivre
Il n'y a pas de commentaire sur cette page. [Afficher commentaires/formulaire]