Wikini

IndentationVisuelle

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-3-93-173-205.compute-1.amazonaws.com
L'utilisateur ne se soucie pas du nombre d'espaces, il suffit qu'il marque "visuellement" une indentation, à l'édition, et le système calcule alors automatiquement le niveau d'indentation voulu.
La compatibilité avec l'ancienne indentation est conservée, à condition de ne pas mélanger des formatages avec tab et des formatages avec des espaces.

Un petit exemple : (cliquer sur Editer cette page pour voir le source).

Un autre exemple :

Un exemple de bogue (connu et à l'étude, cf ci-dessus), placez ceci dans une page :
 - liste 1, ligne 1
   une phrase juste là pour déclencher le bogue
   - liste 2, ligne 1
   - liste 2, ligne 2
   - test
 - liste 1, ligne 2

Le bug est resoluble. Il est dû à l'utilisation de la balise <div> pour les indentations sans puce/marqueur. Il suffit d'utiliser la balise <ul style="list-style: none;"> pour résoudre le problème, mais il faut réécrire une petite partie du code du formateur. La correction fera que la sous liste n'aura pas de puces alors qu'elles sont demandées sur les items "liste2".
Voila un bout de code qui corrige le problème, mais il n'est pas testé dans wakka.php car il est écrit dans une classe de mise en forme indépendante de wikini. Je pense qu'il doit être compatible avec le wakka.php mais je ne l'ai pas testé.
<?php
        
// indented text
        
elseif (preg_match('`(^|\n)(\t+| +)(-|[[:alnum:]]+\))?`'$thing$matches))
        {
            
$closeLI true
            
// test si il faut une NL (par exemple si la liste debute la page)
            
if ($matches[1] != "\n"$br true
            
// ajout un saut de ligne si necessaire (par exemple au debut d'une liste)
            
$result .= ($br "<br />\n" ""); 
            
// pas de NL dans la liste !!!
            
$br 0
            
// recherche du type de la liste
            
if (isset($matches[3]))
            {
                
$newIndentType $matches[3];
            } 
            else
            {
                
$newIndentType '';
            } 
            
// calcul de la balise ouvrante/fermante selon le type de liste
            
if (!$newIndentType)
            {
                
$opener "\n" '<ul style="list-style: none; ">';
                
$closer "</li></ul>\n";
            } elseif (
$newIndentType == '-')
            {
                
$opener "\n<ul>";
                
$closer "</li></ul>\n";
            } 
            else
            { 
                
// NB: <ol type="..."> est deprecié depuis HTML4.01 -> utilisation d'un style a la place
                
if (strpos('i'$matches[3]) !== false$style 'lower-roman';
                elseif (
strpos('I'$matches[3]) !== false$style 'upper-roman';
                elseif (
preg_match('`[0-9]`'$matches[3])) $style 'decimal';
                elseif (
preg_match('`[a-z]`'$matches[3])) $style 'lower-alpha';
                else 
$style 'style="list-style: upper-alpha;"';
                
$opener "\n<ol style=\"list-style: $style;\">";
                
$closer "</li></ol>\n";
            } 
            
// calcul du niveau d'indentation
            // si il y a des tabulations devant la liste alors le niveau = nbr de tab
            
if (strpos($matches[2], "\t") !== false)
            {
                
$newIndentLevel strlen($matches[2]);
                
$newIndentLength $newIndentLevel;
            } 
            else 
// pas de tab => la difference du nbre d'espace definie le niveau d'indentation
            
{
                
$newIndentLevel $oldIndentLevel
                
// longeur de la chaine d'indentaton
                
$newIndentLength strlen($matches[2]);
                if (
$newIndentLength $oldIndentLength)
                { 
                    
// si la chaine d'indentation est plus longue que la precedente
                    // on incremente le niveau d'indentation
                    
$newIndentLevel++; 
                    
// on stock la niveau correspondant a la longueur de la chaine d'indentation
                    
for ($i $oldIndentLength 1$i <= $newIndentLength$i++)
                    {
                        
$newIndentSpace[$i] = $newIndentLevel;
                    } 
                } elseif (
$newIndentLength $oldIndentLength)
                { 
                    
// si la chaine d'indentation est plus courte que la precedente
                    // on recupere le niveau d'indentation correspondant a la longueur de la chaune
                    
$newIndentLevel $newIndentSpace[$newIndentLength];
                } 
            } 
            
// si le nouveau level est plus grand
            
if ($newIndentLevel $oldIndentLevel)
            {
                for (
$i 0$i $newIndentLevel $oldIndentLevel$i++)
                { 
                    
// on ajoute le tag d'ouverture de liste
                    
$result .= $opener
                    
// sauvegarde du tag de fermeture dans la pile
                    
array_push($indentClosers$closer);
                } 
                
$closeLI false;
            } 
            
// si le nouveau level est plus petit
            
else if ($newIndentLevel $oldIndentLevel)
            {
                for (
$i 0$i $oldIndentLevel $newIndentLevel$i++)
                { 
                    
// on depile le tag de fermeture
                    
$result .= array_pop($indentClosers);
                } 
                
$closeLI true;
            } 
            
// si c'est le meme level
            
else if ($newIndentLevel == $oldIndentLevel)
            {
                
$closeLI true;
            } 

            
$result .= ($closeLI?'</li>':'') . "\n<li>";

            
$oldIndentLevel $newIndentLevel;
            
$oldIndentLength $newIndentLength;

            return 
$result;
        } 
?>

Les balises utilisées ici ne sont pas du tout les mêmes que dans le code original, je cherche a être XHTML 1.0 strict et l'attribut type des balises <ol> et <ul> est déprécié depuis HTML4.01.
--GarfieldFr

Superbe !! Avec en plus le soucis d'améliorer la compatibilité XHTML strict. Je dis bravo. Testé en local chez moi, ça marche nickel sauf un tout petit détail : deux listes séparées par deux retours de ligne (donc une ligne vide) ne produisent pas le <br /> attendu... on à trois retours de lignes (\n) à la place. Il me faut mettre trois retours de ligne (donc deux lignes blanches) pour obtenir enfin un <br />. Je n'arrive pas à déboguer ce petit problème. As-tu une idée ? Ce petit bogue résolu je pense qu'on intégrer direct au CVS. Même s'il y a un petit changement au niveau des <ol>, on reste à fonctionnalité identique au niveau du rendu. Je pense donc qu'on peut l'intégrer dans 0.5 et 0.4.4. -- CharlesNepote

Je pense avoir corrigé le bug que tu décris, par ailleurs j'ai fait quelques optimisations et j'ai corrigé le bug suivant:
Je me suis permis de modifier directement le code, voyez l'historique pour la version d'origine de GarfieldFr. -- LordFarquaad

Ok. Ton code fonctionne bien. Ce qui me gène, c'est que ton code fait comme internet explorer : à être tolérant sur ce genre de point, ne risque-t-on pas t'introduire un certains laxisme chez l'utilisateur... J'ai peur d'obtenir ça :
- a
  - a.1
    - a.1.1
   - a.2
     - a.2.1
  - a.3
     - a.3.1

Avantages : meilleure compatibilité XHTML (toutes les balises sont fermées) ; corrige les petites erreurs de l'utilisateur
Inconvénients : risque de compliquer l'écriture d'une liste du fait que l'utilisateur ne sait plus sur quoi aligner son tiret...
Qu'en pensez-vous les autres ?
-- CharlesNepote


Je viens de refaire ton bug, et je ne vois pas en quoi l'absence d'un <br /> entre 2 listes est un problème. Pour séparé 2 listes, tu dois forcément mettre une ligne vide sinon c'est la même liste. De plus, une liste est un block au niveau HTML il n'est pas nécessaire de séparer 2 blocks par un <br />. Le <br /> est à utiliser lorsque tu veux insérer un saut de ligne dans un block, par exemple mettre un saut de ligne dans un paragraphe. Pour moi, une ligne vide entre deux liste n'a pas à générer de <br />.
Je vais étudier la solution de LordFarquaad et le bug qu'il montre. Cela me laisse aussi perplexe de laisser autant de facilité de mal écrire sa liste à l'utilisateur.
--GarfieldFr
<?php
//debut de la fonction : declaration des variables:
    
static $oldIndentLevel 0;    //niveau d'indentation precedent
    
static $oldIndentLength0;    //
    
static $indentClosers = array();
    static 
$newIndentSpace= array();
    static 
$br 1;

// plus loin .....

    // texte indenté
    
if (preg_match('`(^|\n)(\t+|([ ]{1})+)(-|([[:alnum:]]+)\))?`s',$thing,$matches)){
        
$closeLI true;

        
//test si il faut une NL (par exemple si la liste debute la page)
        
if (strpos($matches[1],"\n")==0$br 0;
        
//ajout un saut de ligne si necessaire (par exemple au debut d'une liste)
        
$result .= ($br "<br />\n" "");

        
//pas de NL dans la liste !!!
        
$br 0;

        
//recherche du type de la liste
        
if (isset($matches[4])) {
            
$newIndentType $matches[4];
        } else {
            
$newIndentType '';
        }
        
//calcul de la balise ouvrante/fermante selon le type de liste
        
if (!$newIndentType) {
            
$opener "\n".'<ul style="list-style: none; ">';
            
$closer "</li></ul>\n";
        } else if (
$newIndentType=='-'){
            
$opener "\n<ul>";
            
$closer "</li></ul>\n";
        } else {
            
// NB: <ol type="..."> est deprecié depuis HTML4.01 -> utilisation d'un style a la place
            
if (preg_match('`[0-9]+`',$matches[4])) $style='style="list-style: decimal;"';
            if (
preg_match('`[a-hj-z]+`',$matches[4])) $style='style="list-style: lower-alpha;"';
            if (
preg_match('`[A-HJ-Z]+`',$matches[4])) $style='style="list-style: upper-alpha;"';
            if (
preg_match('`[i]+`',$matches[4])) $style='style="list-style: lower-roman;"';
            if (
preg_match('`[I]+`',$matches[4])) $style='style="list-style: upper-roman;"';
            
$opener "\n<ol $style>";
            
$closer "</li></ol>\n";
        }

        
//calcul du niveau d'indentation
        //si il y a des tabulations devant la liste alors le niveau = nbr de tab
        
if (strpos($matches[2],"\t")){
            
$newIndentLevel strlen($matches[2]);
        } else {    
//pas de tab => la difference du nbre d'espace definie le niveau d'indentation
            
$newIndentLevel=$oldIndentLevel;
            
//longeur de la chaine d'indentaton
            
$newIndentLength strlen($matches[2]);
            if (
$newIndentLength>$oldIndentLength) {
                
//si la chaine d'indentation est plus longue que la precedente
                //on incremente le niveau d'indentation
                
$newIndentLevel++;
                
//on stock la niveau correspondant a la longueur de la chaine d'indentation
                //la boucle for permet de corriger les erreurs de saisie d'espace.
                //$newIndentSpace[$newIndentLength]=$newIndentLevel;
                
for ($i $oldIndentLength 1$i <= $newIndentLength$i++){
                    
$newIndentSpace[$i] = $newIndentLevel;
                }
            } else if (
$newIndentLength<$oldIndentLength)
                
//si la chaine d'indentation est plus courte que la precedente
                //on recupere le niveau d'indentation correspondant a la longueur de la chaune
                
$newIndentLevel=$newIndentSpace[$newIndentLength];
        }
        
//si le nouveau level est plus grand
        
if ($newIndentLevel>$oldIndentLevel){
            for (
$i 0$i $newIndentLevel $oldIndentLevel$i++) {
                
//on ajoute le tag d'ouverture de liste
                
$result .= $opener;
                
//sauvegarde du tag de fermeture dans la pile
                
array_push($indentClosers,$closer);
                
$closeLI false;
            }
        }
        
//si le nouveau level est plus petit
        
else if ($newIndentLevel<$oldIndentLevel){
            for (
$i 0$i $oldIndentLevel $newIndentLevel$i++) {
                
//on depile le tag de fermeture
                
$result .= array_pop($indentClosers);
            }
            
$closeLI true;
        }
        
//si c'est le meme level
        
else if ($newIndentLevel == $oldIndentLevel){
            
$closeLI true;
        }

        
$result .= ($closeLI?'</li>':'')."\n<li>";

        
$oldIndentLevel $newIndentLevel;
        
$oldIndentLength$newIndentLength;

        return 
$result;
    }

//encore plus loin: lorsque on rencontre un \n on ferme les balises de liste

    //nouvelle ligne
    
if ($thing == "\n") {
        
//fermeture des balises de liste
        
$c count($indentClosers);
        for (
$i 0$i $c$i++)    {
            
$result .= array_pop($indentClosers);
            
$br 0;
        }
        
$oldIndentLevel 0;
        
$oldIndentLength0;
        
$newIndentSpace=array();

        
$result .= ($br "<br />\n" "\n");
        
$br 1;
        return 
$result;
    }
?>

Ce code marche très bien sur mon projet et ne souffre d'aucun bug détecté. Les balises se ferment correctement dans tous les cas que j'ai testé. Comme précisé plus haut, ce code provient d'un projet personnel ou j'ai réécrit une partie de la syntaxe WikiNi. Pour être tout à fait complet, il faudrait que je publie le code de la classe en entier, mais elle serait imcomplète pour l'utilisation dans WikiNi (manque les mots wiki et certains types de liens par exemple)--GarfieldFr



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