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).
- indentation de premier niveau (avec 3 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de premier niveau (avec 3 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de troisième niveau (avec 3 + 2 + 5 espaces)
- indentation de troisième niveau (avec 3 + 2 + 5 espaces)
- indentation de troisième niveau (avec 3 + 2 + 5 espaces)
- indentation de premier niveau (avec 3 espaces)
- indentation de premier niveau (avec 3 espaces)
- indentation de premier niveau (avec 3 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de premier niveau (avec 3 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de deuxième niveau (avec 3 + 2 espaces)
- indentation de troisième niveau (avec 3 + 2 + 5 espaces)
- indentation de troisième niveau (avec 3 + 2 + 5 espaces)
- indentation de troisième niveau (avec 3 + 2 + 5 espaces)
- indentation de premier niveau (avec 3 espaces)
- indentation de premier niveau (avec 3 espaces)
Un autre exemple :
- premier niveau
- deuxieme niveau
- troisième niveau
- troisième niveau
- deuxieme niveau
- encore un niveau...
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 n'ai pas bien compris ton bug, tu pourrais me donner un exemple ? --GarfieldFr
Je pense avoir corrigé le bug que tu décris, par ailleurs j'ai fait quelques optimisations et j'ai corrigé le bug suivant:
- premier niveau
- deuxieme niveau
- troisième niveau
- troisième niveau
- deuxieme niveau (ou premier ? dans ma solution: 2e) - génère une notice
- premier niveau
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
- Il ne faut surtout pas être trop tolérant dans le code. Tous ce que l'on gagne, c'est des futurs embètements. L'exemple de LordFarquaad ne devrait pas marcher. --GarfieldFr
- Quels embètements risque-t'on ?
- Puisque le sujet n'est pas tranché, je propose, dans un premier temps, de publier un mix entre le code de GarfieldFr et LordFarquaad, retenant la correction de bogue de GarfieldFr + la correction relative au saut de ligne de LordFarquaad. Quant à la fonctionnalité de "correction d'erreur" de LordFarquaad, je la laisse de côté en attendant plus ample débat. -- CharlesNepote
- Actuellement le code marche sauf qu'il fait sauter l'apparence et qu'il en résulte du XHTML non valide (balises non fermées ou fermées dans le désordre). A mon sens il faut bien une solution à ce problème. Ce qu'on peut éventuellement faire c'est fermer complètement la liste si jamais on tombe sur ce genre de problème, et afficher l'élément hors liste. J'en profite pour reproduire le bug que j'avais testé dans le BacASable (le numéro correspond au nombre d'espaces):
- 1
- 1
- 7
- 5... en sous élément du 7 !!! et oui, dans la première partie de cette liste le 5 était un sous-élément du 3 qui était de niveau 2, comme l'est le 7 dans la seconde partie...
- Au fait j'ai réalisé un code qui, côté programmation, est très simple, côté affichage est très logique, mais par contre assez difficile à expliquer... Je l'ai mis en place ici en tentant d'expliquer comment ça marche, les valeurs entre crochets dans le dernier exemple expriment comment ça marche côté programmation. -- LordFarquaad
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
- Au fait je m'étais trompé je pense au niveau de la séparation des listes: c'est si le premier carractère n'est pas un retour à la ligne qu'il fallait un br. Dans la version que j'avais proposée cela ajoutait des br à pratiquement tous les éléments de la liste... Sinon c'est vrai qu'en toute logique il ne faut pas un br s'il n'y a qu'une seule ligne vide... Quoi que si on n'en met pas, visuellement c'est comme s'il n'y avait qu'une seule liste... -- LordFarquaad
- Non, ca depend du CSS et probablement du navigateur. Sans aucun CSS de défini, les deux listes sont bien séparé par un interligne plus important (sur Firefox). Cela montre bien qu'il n'est pas nécessaire d'ajouter des <br />. Dans mon code précedent, j'avais oublié de publier certain bouts. Voici le code complet avec la correction automatique d'erreur de saisie. La partie oubliée concernait la fermeture des balises.
<?php
//debut de la fonction : declaration des variables:
static $oldIndentLevel = 0; //niveau d'indentation precedent
static $oldIndentLength= 0; //
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;
$oldIndentLength= 0;
$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