Module:Taxobox
[voir] [modifier] [historique] [purger]
Ce module permet de créer des taxobox, infobox taxinomiques permettant de décrire un taxon existant dans une classification scientifique des espèces.
Utilisation
modifierFonctions exportables :
taxobox()
– fonction unique pour la création d'une taxobox (prend tous ses paramètres dans la frame parente).convertisseur()
– non fonctionnel (fonction prenant en unique paramètre une taxobox au format modèles et retournant la syntaxe au format module).
Autres fonctions :
est_dans_liste(mot, liste)
– retourne la position de mot dans liste si présent ou nillecture_parametres(ligne, depart, desc)
– analyse ligne (une table de textes) à partir de l'élément depart en fonction de la description de format desc (voir plus loin la syntaxe d'un format). Retourne une table où les valeurs indiquées dans le format sont fixées (ou nil). Si une erreur dans l'analyse survient le champs erreurs contient la description de l'erreur (nil sinon) et le contenu de la table retourné est non prédictible.
Modules externes et autres éléments dont ce module a besoin pour fonctionner :
- Module:Taxobox-outils : fonctions de traitement effectif des éléments d'une taxobox, plus quelques fonctions utilitaires
- Module:Taxobox-data : tables et fonctions d'accès associées contenant toutes les données relatives à la génération des taxobox
- Module:Taxobox-briques : fonction fournissant les briques de base pour construire des infobox
La documentation de ce module est générée par le modèle {{Documentation module}}.
Elle est incluse depuis sa sous-page de documentation. Veuillez placer les catégories sur cette page-là.
Les éditeurs peuvent travailler dans le bac à sable (créer).
Voir les statistiques d'appel depuis le wikicode sur l'outil wstat et les appels depuis d'autres modules.
-- module principal (de test) pour générer des taxobox.
-- contient la fonction principale (et unique) "taxobox"
-- l'autre fonction (convertisseur) n'est pas fonctionnelle.
-- il reste des choses à faire, nettoyer…
local z = {}
-- les boîtes à outils
local data = require "Module:Taxobox-data"
local briques = require "Module:Taxobox-briques"
local tools = require "Module:Taxobox-outils"
-- preparation : table "globale" contenant les divers paramètres communs
-- contient aussi les tables et éléments pour les retours d'info des fonctions
z.configuration = {}
-- la "frame", nécessaire pour faire du preprocess si besoin
z.configuration.frame = nil -- fram
-- paramètres qui sont des données
z.configuration.regne = nil -- le règne
z.configuration.nv = nil -- le(s) nom(s) vernaculaire(s) si présent
-- informations sur l'article
z.configuration.titre_page = nil -- le titre réel de l'article
z.configuration.article = nil -- le namespace de la page (true=article, false=autre)
-- titre forcé : faire comme si c'était le titre de l'article (implique NS=0)
z.configuration.force_titre = nil
-- informations sur la taxobox (sa structure)
z.configuration.div_nb = 0 -- compte des ouvertures / fermertures de <div>
z.configuration.table_nb = 0 -- compte des ouvertures / fermetures de <table>
z.configuration.fermeture_taxobox = nil -- état de la taxobox (redondant avec div_nb ?)
-- informations calculées
z.configuration.titre_article = nil -- titre mis en forme de l'article (pour modification affichage)
z.configuration.titre_taxobox = nil -- titre de la taxobox (mis en forme) calculé d'après les infos
z.configuration.titre_ns = nil -- si true → article titré avec le (un) nom scientifique, sinon nom vernaculaire
z.configuration.regne_affiche = nil -- le nom wikifié correspondant au règne
z.configuration.regne_lien = nil -- le lien vers lequel pointe ce règne
z.configuration.sous_titre = "" -- le sous-titre (éventuel) à insérer
-- zones de stockage d'information pour les retours
z.configuration.r_categories = {} -- stockage des catégories retournées par les fonctions
z.configuration.r_err_categories = {} -- stockage des catégories d'erreur retournées par les fonctions
z.configuration.r_erreurs = {} -- stockage des erreurs retournées par les fonctions
-- fonctions d'accès pour remplir les informations (cat, err-cat, err)
z.configuration.f_categories = nil -- fonction d'ajout d'une catégorie
z.configuration.f_err_categories = nil -- fonction d'ajout d'une catégorie d'erreur
z.configuration.f_erreurs = nil -- fonction d'ajout d'une erreur { type, message }
-- les éléments de contrôle de la sortie
z.configuration.c_titre = nil -- la gestion du titre (oui, non, auto)
z.configuration.c_sous_titre = nil -- la gestion du sous-titre (oui, non, auto)
z.configuration.c_categories = nil -- la gestion des catégories (en ligne, boîte, non, auto)
z.configuration.c_err_categories = nil -- la gestion des catégories d'erreurs (en ligne, boîte, non, auto)
z.configuration.c_erreurs = nil -- la gestion des messages d'erreur (oui, non, auto)
-- les éléments réservés aux développeurs
z.configuration.c_raw = nil -- affichage "brut" de la taxobox
z.configuration.c_debug = nil -- mode debug. Ne fait rien actuellement
-- l'ensemble des paramètres non-nommés, sous forme de table de tables (1 par ligne)
local descriptions = {}
local nb_lignes -- nombre de lignes dans la description
-- variables d'état de la taxobox : contient les états en cours
local etat_precedent = "" -- ce qu'on a traité juste avant
local liste_taxons = {} -- liste des taxons trouvés
local nb_taxons -- nombre de lignes dans liste_taxons
local cible_taxon = nil -- si présent, l'utiliser plutôt que nb_taxons pour choix du titre
local nb_debut = 0 -- pour gérer les ouvertures / fermetures
local nb_cites = 0 -- pour gérer la proximité
local nb_uicn = 0 -- pour gérer la proximité
local pdebug = "" -- pour le mode debug
-- fonctions de manipulation des infos
function z.ajoute_r_categories(nom)
if (nom == nil) then
return
end
table.insert(z.configuration.r_categories, nom)
end
function z.ajoute_r_err_categories(nom)
if (nom == nil) then
return
end
table.insert(z.configuration.r_err_categories, nom)
end
function z.ajoute_r_erreurs(tp, desc)
if (tp ~= nil and tp ~= "" and desc ~= nil and desc ~= "") then
local ll = ""
if (type(z.configuration.ligne_courante) == "string") then
ll = z.configuration.ligne_courante
elseif (type(z.configuration.ligne_courante) == "table") then
ll = table.concat(z.configuration.ligne_courante, "|")
else
ll = "- pas d'information -"
end
table.insert(z.configuration.r_erreurs, {tp,desc .. "<br/>(" .. ll .. ")" })
end
end
-- initialisation des fonctions de traitement de catégorie
z.configuration.f_categories = z.ajoute_r_categories
z.configuration.f_err_categories = z.ajoute_r_err_categories
z.configuration.f_erreurs = z.ajoute_r_erreurs
-- cette fonction nettoie les blancs au début et à la fin du texte. Utile pour nettoyer
-- les paramètres reçus qui peuvent contenir des blancs selon la mise en forme à l'appel
function z.nettoie(nom)
-- histoire de ne pas générer d'erreur
if (nil == nom) then
return nil
end
local tmp = string.gsub (nom, "^[%s]*", "")
return string.gsub (tmp, "[%s]*$", "")
end
-- indique si un mot est dans une liste. Si oui retourne la position dans la liste
function z.est_dans_liste(mot, liste)
local i = 1
if (liste == nil) then
return 0
end
while (liste[i] ~= nil) do
if (liste[i] == mot) then
return i
end
i = i + 1
end
return 0
end
-- lecture d'une ligne de paramètres
-- desc est la description symbolique de ce qu'on attend
-- ligne est une table (de string) contenant la ligne découpée
-- depart est l'offset dans la table où commencer
-- Retourne une table où se trouvent fixées les valeurs trouvées
-- Format de la description :
-- {
-- ["noname"] = { "key1", "key2", ... },
-- ["flags"] = { { { "f1", "f1b", ... }, "key" }, { { "f2", "f2b", ... }, "key2" }, ... },
-- |"values"] = { { { "v1", "v1b", ... }, "key" }, { { "v2", "v2b", ... }, "key2" }, ... }
-- }
-- noname : paramètres sans nom sur la ligne. La fonction associe tout paramètre qui n'est ni un
-- flag ni un value à la liste de mots-clés. Dans la table retournée on aura tab["key1"] = "le premier champs non nommé",
-- tab["key2" = "le 2ème champs non nommé"... Ceux non présents valent nil. Si trop de paramètres non nommés sont présents
-- les derniers sont ignorés et une erreur est retournée (voir la gestion des erreurs plus bas)
-- flags : paramètres ayant un nom et qui ne sont gérés que par présent/absent. La fonction compare chaque paramètre à la liste
-- des mots-clés possibles pour chaque flag (f1, f1b pour le premier, f2, f2b…). Si l'un est présent la fonction fixe
-- tab["key"] = true (nil sinon)
-- si un flag est donné plus d'une fois cela génère une erreur
-- values : identique aux flags, mais la fonction cherche une valeur associée, qui est le paramètre suivant. Cette valeur
-- est passée par tab["key"] = "valeur lue".
-- Si une value n'a pas de valeur (dernier élément de la liste) ou est donnée plusieurs fois cela génère une erreur
-- Erreurs : si tab["erreurs"] est non nil / non vide c'est qu'une erreur s'est produite. tab["erreurs"] contient un message
-- expliquant l'erreur
-----
----- TODO : remplacer z.ajoute_erreur ici pour transmettre l'erreur à celui qui appelle.
-----
function z.lecture_parametres(ligne, depart, desc)
local i = depart
local buf = ""
local res = {}
local j
local tmpf
-- on parcours les entrées
while (ligne[i] ~= nil) do
v = z.nettoie(ligne[i])
--- on cherche si 'v' correspond à un élément des descriptions
j = 1
if (desc["flags"] == nil) then
tmpf = 0 -- pas de flags
else
while (desc["flags"][j] ~= nil) do
tmpf = z.est_dans_liste(v, desc["flags"][j][1])
if (tmpf > 0) then
break
end
j = j + 1
end
end
if (tmpf > 0) then
-- on a trouvé, c'est un flag
-- on vérifie qu'il n'est pas déjà donné
if (res[desc["flags"][j][2]] ~= nil) then
res["erreurs"] = "Élément ''" .. ligne[i] .. "'' en multiples exemplaires"
end
-- quoi qu'il en soit c'est le dernier qui gagne
res[desc["flags"][j][2]] = true
else
-- pas un flag, on regarde les "values"
j = 1
if (desc["values"] == nil) then
tmpf = 0
else
while (desc["values"][j] ~= nil) do
tmpf = z.est_dans_liste(v, desc["values"][j][1])
if (tmpf > 0) then
break
end
j = j + 1
end
end
if (tmpf > 0) then
-- on a trouvé, c'est un values
-- on vérifie qu'il y a un élément en plus
if (ligne[i+1] == nil) then
-- c'est une erreur
res.erreurs = "Valeur ''" .. v .. "'' sans contenu (case suivante)."
else
-- on vérifie qu'il n'est pas déjà donné
if (res[desc["values"][j][2]] ~= nil) then
res.erreurs = "Élément ''" .. ligne[j] .. "'' en multiples exemplaires."
end
-- quoi qu'il en soit c'est le dernier qui gagne
res[desc["values"][j][2]] = z.nettoie(ligne[i+1])
-- on saute l'élément
i = i + 1
end
else
-- c'est un paramètre non nommé
-- on cherche le premier non nommé qui soit nil
j = 1
while (desc["noname"][j] ~= nil) do
if (res[desc["noname"][j]] == nil) then
break
end
j = j + 1
end
if (desc["noname"][j] == nil) then
-- donc il y a trop de paramètres -> erreur
res.erreurs = "Trop de paramètres"
else
-- on fixe sa valeur
res[desc["noname"][j]] = v
end
end
end
-- entrée suivante
i = i + 1
end
return res
end
--- fonctions de traitement des lignes de description
-- wrapper effectuant la lecture des paramètres et traitant les erreurs
function z.traite_avec_erreur(ligne, syntaxe)
local params = z.lecture_parametres(ligne, 2, syntaxe)
if (params.erreurs ~= nil) then
return nil, "syntaxe", params.erreurs
end
return params, nil, nil
end
-- devrait disparaitre aussi : il faut revoir l'appel explicite dans la fonction principale
-- fin de la taxobox. Syntaxe :
-- fin
function z.traite_fin(ligne)
-- si la taxobox n'est pas ouverte
if (fermeture_taxobox == true) then
z.ajoute_r_erreurs("syntaxe", "Fermeture de taxobox sans qu'elle soit ouverte.")
z.ajoute_r_err_categories("Taxobox avec erreur/syntaxe")
return ""
end
-- on indique que la taxobox est fermée
fermeture_taxobox = true
local tmp = tools.t_vraie_fin(z.configuration)
return tmp
end
-- prend une ligne en paramètre et appelle la bonne fonction, et gère les erreurs
function z.traite_ligne(ligne)
local prems
local res = ""
local courant
if (ligne == nil) then
z.ajoute_r_erreurs("interne (traite_ligne)", "La ligne courante vaut ''nil''.")
z.ajoute_r_err_categories("Taxobox avec erreur/interne")
return nil
end
prems = ligne[1]
if (prems == nil) then
z.ajoute_r_erreurs("interne (traite_ligne)", "Pas de premier élément dans la ligne reçue.")
z.ajoute_r_err_categories("Taxobox avec erreur/interne")
return nil
end
-- on récupère la ligne décrivant cet élément
local desc = tools.d_syntaxe[prems]
if (desc == nil) then
z.ajoute_r_erreurs("syntaxe", "Le mot-clé " .. prems .. " est inconnu.")
z.ajoute_r_err_categories("Taxobox avec erreur/syntaxe")
return nil
end
-- desc contient dans l'ordre le niveau de criticité de la ligne (1/2/3),
-- la description du format de la ligne, la fonction à appeler
-- on évalue la ligne
local vals, stl, msg = z.traite_avec_erreur(ligne, desc[2])
-- erreur de syntaxe ?
if (vals == nil) then
-- on retourne une erreur, fatale si demandé
z.ajoute_r_erreurs(stl, msg)
z.ajoute_r_err_categories("Taxobox avec erreur/" .. stl)
if (desc[1] == 2) then
return nil -- erreur fatale
else
return "" -- ligne ignorée
end
end
-- on appelle la fonction de traitement
courant = ligne[1] -- on note l'élément en cours de traitement
z.configuration.ligne_courante = ligne -- pour les erreurs
local reterr, tmp = pcall( desc[3], vals, z.configuration )
if (reterr ~= true) then -- erreur
if (desc[1] == 2) then
-- pas de gestion des messages d'erreur+cat : c'est fait dans les fonctions
return nil -- erreur fatale
else
-- pas de gestion des messages d'erreur+cat : c'est fait dans les fonctions
return "" -- ligne ignorée
end
end
-- si tmp == nil et qu'on est là c'est qu'on ignore la ligne :
if (tmp == nil) then
tmp = ""
end
--- ici on insert les tests de cohérence sur la structure des éléments
-- début doit être le premier. Il ne peut y en avoir qu'un
if (courant == "début" and nb_debut > 0) then
z.ajoute_r_erreurs("structure", "Plus de un ''début'' donné.")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
return nil -- c'est fatal
end
if (courant ~= "début" and nb_debut == 0) then
z.ajoute_r_erreurs("structure", "Élément ''" .. courant .. "'' avant un ''début''.")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
return nil -- c'est fatal
end
if (courant == "début") then
nb_debut = nb_debut + 1
end
-- si on sort d'un "rang" on doit fermer la table
if ( (etat_precedent == "rang" or etat_precedent == "conflit") and (courant ~= "rang" and courant ~= "conflit") ) then
res = res .. "</table>\n"
z.configuration.table_nb = z.configuration.table_nb - 1
end
-- si on rentre dans un "rang" il faut qu'on soit dans une table.
-- ici on accepte mais on génère une erreur
if ( (courant == "rang" or courant == "conflit") and z.configuration.table_nb == 0) then
z.ajoute_r_erreurs("structure", "Élément ''" .. courant .. "'' en déhors d'une zone de classification.")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
-- on ouvre une table (pas propre) pour traiter
res = res .. "<table>"
end
-- rang/conflit : un rang ne peut apparaître que :
-- - après un autre rang (on est dans la classification)
-- - après "début" (sauf si phylo est indiqué)
-- - après "bandeau phylo" (non implémenté encore)
-- dans les autres cas : erreur, ignore ou corrige (<table[/]>) selon option
-- légende/répartition légende : une légende ne peut que suivre une légende ou une image
-- taxon : les taxons devraient être donnés à la suite, pas séparés
if (courant == "taxon" and (etat_precedent ~= "taxon" and etat_precedent ~= "rang" and etat_precedent ~= "conflit") ) then
z.ajoute_r_erreurs("structure", "Élément ''taxon'' à une position incorrecte.")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
end -- mais ce n'est pas fatal
-- UICN / CITES : devraient être groupés s'il y en a plusieurs ?
if (courant == "cites") then
if (nb_cites > 0 and etat_precedent ~= "cites") then
z.ajoute_r_erreurs("structure", "Élément ''CITES'' multiples mais non consécutifs.")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
end
nb_cites = nb_cites + 1
end
if (courant == "uicn") then
if (nb_uicn > 0 and etat_precedent ~= "uicn") then
z.ajoute_r_erreurs("structure", "Élément ''UICN'' multiples mais non consécutifs.")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
end
nb_uicn = nb_uicn + 1
end
-- synonymes / taxons : devrait être au plus près du dernier taxon
-- ...
-- on ajoute l'élément
res = res .. tmp
-- bascule courant / précédent
if (courant ~= nil) then -- on ne touche pas si erreur car on n'a rien fait
etat_precedent = courant
end
-- on retourne le résultat
return res
end
-- cette fonction traite tous les paramètres non-nommés pour créer la table globale associée
-- retourne le nombre total
function z.traite_parametres(pframe)
local k, v
local ligne = {}
local pos = 1
local pd = 1
for k,v in pframe:argumentPairs() do
if (type(k) == "number") then
local temp = string.sub(v, -1)
local txt = z.nettoie(v)
if (pos == 1) then
-- le premier est passé en minuscules
if (txt ~= nil) then
ligne[pos] = string.lower(txt)
else
ligne[pos] = txt
end
else
ligne[pos] = txt
end
pos = pos + 1
if (temp == "\n") then
descriptions[pd] = ligne
pd = pd + 1
ligne = {}
pos = 1
end
end
end
return pd - 1
end
-- retourne vrai si le mot-clé "titre" ou "en titre" est présent
-- dans la table, sinon faux (ainsi qu'en cas d'erreur)
function z.presence_titre(lst)
if (lst == nil or type(lst) ~= "table") then
return false
end
local i = 1
while (lst[i] ~= nil) do
if (type(lst[i]) == "string") then
if (lst[i] == "titre" or lst[i] == "en titre") then
return true
end
end
i = i + 1
end
return false
end
-- cette fonction cherche toutes les occurrences de "taxon" pour déterminer s'il y en a et combien
-- génère la liste des taxons qui est une table { rang, nom } et retourne le nombre trouvé
-- ils sont classés dans l'ordre
-- si une ligne taxon est invalide elle est ignorée (ici)
-- si le mot-clé "titre" ou "en titre" est présent le 3ème champs est mis à vrai
function z.cherche_taxons()
local nb = 0
local pos = 1
-- tant qu'il y a des entrées
while (descriptions[pos] ~= nil) do
-- si c'est "taxon"
if (descriptions[pos][1] == "taxon") then
local rang = descriptions[pos][2]
local nom = descriptions[pos][3]
-- gestion des erreurs
if (rang ~= nil and nom ~= nil) then
-- présence de "titre" ?
local ttl = false
if (z.presence_titre(descriptions[pos])) then
ttl = true
cible_taxon = nb + 1
end
-- on l'ajoute
nb = nb + 1
liste_taxons[nb] = { rang, nom, ttl }
end
end
pos = pos + 1
end
return nb
end
-- utilise liste_taxons pour trouver les titres
function z.cherche_titres(frame)
local pos = 1
-- en premier lieu on cherche le taxon le plus "bas" pour le titre de la taxobox
local ligne
if (cible_taxon ~= nil) then
ligne = liste_taxons[cible_taxon]
if (ligne == nil) then
-- protection
ligne = liste_taxons[nb_taxons]
z.ajoute_r_erreurs("interne/cible_taxon", "cible_taxon=" .. cible_taxon .. " alors que nb_taxons=" .. nb_taxons .. ", retour à ''nil''.")
z.ajoute_r_err_categories("Taxobox avec erreur/interne")
end
else
ligne = liste_taxons[nb_taxons]
end
z.configuration.titre_taxobox = tools.formate_ns(z.configuration.regne, ligne[1], ligne[2], false, false)
-- on découpe le titre de l'article pour extraire la partie homonymie
local tmp = tools.decoupe_homonymie(z.configuration.titre_page)
-- on cherche dans la liste des taxons si l'un d'entre-eux correspond au nom (sans partie homonynie)
local trouve = 0
for i = 1, nb_taxons do
if (tmp[1] == liste_taxons[i][2]) then
trouve = i
-- si celui qui correspond au titre n'est pas le dernier on insert une erreur+cat
-- sauf si il est explicitement indiqué comme titre
if (i ~= nb_taxons) then
if (liste_taxons[i][3] == false) then
z.ajoute_r_erreurs("structure/taxons", "Taxobox gigogne mais article non titré avec le taxon le plus bas")
z.ajoute_r_err_categories("Taxobox avec erreur/structure")
end
end
break
end
end
-- si pas trouvé : probablement titré en nom vernaculaire
if (trouve == 0) then
-- on ne touche pas au titre
z.configuration.titre_article = nil
-- on met en sous-titre la liste des taxons
for i = 1, nb_taxons do
-- on met en forme le nom scientifique
local ttr = tools.formate_ns(z.configuration.regne, liste_taxons[i][1], liste_taxons[i][2], false, false)
if (i < nb_taxons) then
z.configuration.sous_titre = z.configuration.sous_titre .. ttr .. ", "
else
z.configuration.sous_titre = z.configuration.sous_titre .. ttr
end
end
else
-- la mise en forme du titre
z.configuration.titre_article = tools.formate_ns(z.configuration.regne, liste_taxons[trouve][1], tmp[1], true, false)
if (tmp[2] ~= nil) then
z.configuration.titre_article = z.configuration.titre_article .. " " .. tmp[2]
end
-- puisque NS on ajoute les NV en sous-titre si présents
if (z.configuration.nv == nil or z.configuration.nv == "") then
z.configuration.sous_titre = nil
else
z.configuration.sous_titre = z.configuration.nv
end
end
end
function z.essai(frame)
tools.t_test(nil, z.configuration)
if (z.configuration.r_erreurs ~= nil) then
return z.configuration.r_erreurs[1][1] .. " : " .. z.configuration.r_erreurs[1][2] .. "<br/>"
else
return "Aucune retour.<br/>"
end
end
-- génère une box lisant les erreurs (selon le mode)
function z.box_erreurs(mode)
local tx = ""
local pos = 1
if (mode == "non" or z.configuration.r_erreurs == nil or z.configuration.r_erreurs[1] == nil) then
return "" -- rien (rien à faire ou mode "pas d'erreurs")
end
-- si mode auto et article → on ne fait rien non plus
if (mode == "auto" and z.configuration.article == true) then
return ""
end
-- donc là on affiche (soit mode="oui" soit mode="auto" + article)
tx = tx .. briques.t_debut("error", "Erreurs détectées")
while (z.configuration.r_erreurs[pos] ~= nil) do
tx = tx .. "<small>" .. z.configuration.r_erreurs[pos][1] .." : " .. z.configuration.r_erreurs[pos][2] .. "</small>"
pos = pos + 1
end
tx = tx .. briques.t_end()
return tx
end
-- "pousse" la table de catégories selon le bon mode
function z.mef_categories(liste, mode, msg1, msg2)
local ret = ""
-- vide, ou bien mode = "non"
if (mode == "non" or liste == nil or liste[1] == nil) then
return ""
end
local t -- 1=inline, 2=box
if (mode == "en ligne") then
t = 1
elseif (mode == "boîte") then
t = 2
else -- si mode "auto" on regarde dans quel espace on est
if (z.configuration.article == true) then
t = 1 -- dans les articles mode inline
else
t = 2 -- sinon mode box
end
end
-- mode boite : entête
if (t == 2) then
ret = ret .. briques.t_debut(msg1, msg2)
end
local pos = 1
while (liste[pos] ~= nil) do -- on parcours
local p1 = nil -- catégorie
local p2 = nil -- clé éventuelle
if (type(liste[pos]) == "string") then
p1 = liste[pos]
p2 = nil
elseif (type(liste[pos]) == "table") then
p1 = liste[pos][1] or "Taxobox avec erreur/interne"
p2 = liste[pos][2]
else
p1 = "Taxobox avec erreur/interne"
p2 = nil
end
if (t == 1) then
if (p2 == nil) then
ret = ret .. "[[Catégorie:" .. p1 .. "]]"
else
ret = ret .. "[[Catégorie:" .. p1 .. "|" .. p2 .. "]]"
end
else
if (p2 == nil) then
ret = ret .. "[[:Catégorie:" .. p1 .. "|" .. p1 .. "]]<br/>"
else
ret = ret .. "[[:Catégorie:" .. p1 .. "|" .. p1 .. " (" .. p2 .. ")]]<br/>"
end
end
pos = pos + 1
end
-- mode boite : la fin
if (t == 2) then
ret = ret .. briques.t_end()
end
return ret
end
-- génère une box listant les catégories ou les incluant (selon le mode)
function z.box_categories()
local tx = ""
local pos = 1
-- categories "normales"
tx = tx .. z.mef_categories(z.configuration.r_categories, z.configuration.c_categories, "", "Catégories non incluses")
-- catégories d'erreur
tx = tx .. z.mef_categories(z.configuration.r_err_categories, z.configuration.c_err_categories, "error", "Catégories d'erreur non incluses")
return tx
end
-- fonction principale
function z.taxobox(frame)
local pframe = frame:getParent()
local args = pframe.args
local tx = ""
local tmp
-- on conserve la frame
z.configuration.frame = frame
-- on récupère le NAMESPACE tout de suite, pour que les briques erreur puissent catégoriser correctement
z.configuration.article = frame:preprocess("{{NAMESPACE}}") -- le namespace de la page
if (z.configuration.article == "") then
-- c'est un article
z.configuration.article = true
else
z.configuration.article = false
end
-- -- gestion des paramètres nommés (debug, options, éléments obligatoires)
-- - paramètres éditoriaux
-- on récupère le règne
z.configuration.regne = z.nettoie(args["règne"]) or nil
-- pas de règne, erreur tout de suite
if (z.configuration.regne == nil) then
return briques.t_erreur("Le paramètre nommé ''règne'' est obligatoire.", "règne", z.configuration)
end
-- on recupère les noms vernaculaires
z.configuration.nv = z.nettoie(args["nv"] or args["nom vernaculaire"] or args["noms vernaculaires"]) or nil
-- - paramètres modifiant le comportement (note : passer ça en minuscules)
-- titre : oui, non, auto → contrôle la modification (éventuelle) du titre
z.configuration.c_titre = z.nettoie(args["titre"]) or nil
if (z.configuration.c_titre == nil) then
z.configuration.c_titre = data.defauts.titre -- mode par défaut
end
-- validation du paramètre
if (z.configuration.c_titre == "boite") then
z.configuration.c_titre = "boîte"
end
if (z.configuration.c_titre ~= "oui" and z.configuration.c_titre ~= "non" and z.configuration.c_titre ~= "boîte" and z.configuration.c_titre ~= "auto") then
return briques.t_erreur("Le paramètre nommé ''titre'' ne peut prendre que les valeurs ''oui'', ''non'' ou ''auto''.", "titre", z.configuration)
end
-- sous-titre : oui, non, auto → contrôle la modification (éventuelle) du sous-titre
z.configuration.c_sous_titre = z.nettoie(args["sous-titre"]) or nil
if (z.configuration.c_sous_titre == nil) then
z.configuration.c_sous_titre = data.defauts.sous_titre -- mode par défaut
end
-- validation du paramètre
if (z.configuration.c_sous_titre == "boite") then
z.configuration.c_sous_titre = "boîte"
end
if (z.configuration.c_sous_titre ~= "oui" and z.configuration.c_sous_titre ~= "non" and z.configuration.c_sous_titre ~= "boîte" and z.configuration.c_sous_titre ~= "auto") then
return briques.t_erreur("Le paramètre nommé ''sous-titre'' ne peut prendre que les valeurs ''oui'', ''non'' ou ''auto''.", "sous-titre", z.configuration)
end
-- erreurs : oui, non, auto → contrôle l'insertion des messages d'erreur
z.configuration.c_erreurs = z.nettoie(args["erreurs"]) or nil
if (z.configuration.c_erreurs == nil) then
z.configuration.c_erreurs = data.defauts.erreurs -- mode par défaut
end
-- validation du paramètre
if (z.configuration.c_erreurs ~= "oui" and z.configuration.c_erreurs ~= "non" and z.configuration.c_erreurs ~= "auto") then
return briques.t_erreur("Le paramètre nommé ''erreurs'' ne peut prendre que les valeurs ''oui'', ''non'' ou ''auto''.", "erreurs", z.configuration)
end
-- catégories : en ligne, boite, non, auto → contrôle l'insertion des catégories "normales"
z.configuration.c_categories = z.nettoie(args["catégories"] or args["catégorie"] or args["categories"] or args["categorie"]) or nil
if (z.configuration.c_categories == nil) then
z.configuration.c_categories = data.defauts.categories -- mode par défaut
end
-- validation du paramètre
if (z.configuration.c_categories == "boite") then
z.configuration.c_categories = "boîte"
end
if (z.configuration.c_categories ~= "en ligne" and z.configuration.c_categories ~= "boîte" and z.configuration.c_categories ~= "non" and z.configuration.c_categories ~= "auto") then
return briques.t_erreur("Le paramètre nommé ''catégories'' ne peut prendre que les valeurs ''en ligne'', ''boîte'', ''non'' ou ''auto''.", "catégories", z.configuration)
end
-- catégories d'erreurs : en ligne, boite, non, auto → contrôle l'insertion des catégories d'erreurs
z.configuration.c_err_categories = z.nettoie(args["catégories erreurs"] or args["catégorie erreurs"] or args["categories erreurs"] or args["categorie erreurs"]) or nil
if (z.configuration.c_err_categories == nil) then
z.configuration.c_err_categories = data.defauts.err_categories -- mode par défaut
end
-- validation du paramètre
if (z.configuration.c_err_categories == "boite") then
z.configuration.c_err_categories = "boîte"
end
if (z.configuration.c_err_categories ~= "en ligne" and z.configuration.c_err_categories ~= "boîte" and z.configuration.c_err_categories ~= "non" and z.configuration.c_err_categories ~= "auto") then
return briques.t_erreur("Le paramètre nommé ''catégories erreurs'' ne peut prendre que les valeurs ''en ligne'', ''boîte'', ''non'' ou ''auto''.", "catégories erreurs", z.configuration)
end
-- - paramètres de debug (réservés aux développeurs)
-- paramètre "raw" : sortie brute, non interprétée, du résultat (debug)
z.configuration.c_raw = z.nettoie(args["raw"]) or nil
if (z.configuration.c_raw == nil) then
z.configuration.c_raw = data.defauts.raw
end
if (z.configuration.c_raw == "oui") then
tx = "<nowiki>"
end
-- paramètre "debug" : ne fait presque rien actuellement
z.configuration.c_debug = z.nettoie(args["debug"]) or nil
if (z.configuration.c_debug == nil) then
z.configuration.c_debug = data.defauts.debug
end
-- paramètre "force titre" : fait comme si c'était un article dont le titre est indiqué
z.configuration.force_titre = z.nettoie(args["force titre"]) or nil
-- on analyse le règne indiqué, pour validation/préparation
z.configuration.regne_affiche = data.premier_regne(z.configuration.regne) -- le nom wikif du règne
if ( nil == z.configuration.regne_affiche or "" == z.configuration.regne_affiche ) then
-- ce n'est pas un règne valide
return briques.t_erreur("Le paramètre nommé ''règne'' n'est pas valide (" .. z.configuration.regne .. ").", "règne", z.configuration) .. z.box_erreurs("oui") -- on force l'erreur
end
local tmp2 = data.est_rang("règne")
z.configuration.regne_lien = tmp2[2][1]
-- on récupère les informations externes sur l'article en cours
if (z.configuration.force_titre ~= nil) then
-- dans ce cas on utilise ce titre-là
z.configuration.titre_page = z.configuration.force_titre
else
z.configuration.titre_page = frame:preprocess("{{PAGENAME}}") -- titre de la page
end
-- on génère la table qui décrit la taxobox
nb_lignes = z.traite_parametres(pframe)
if (nb_lignes == nil or nb_lignes <= 0) then
-- une taxobox vide !
return briques.t_erreur("La taxobox est vide", "syntaxe", z.configuration) .. z.box_erreurs("oui") -- on force l'erreur
end
-- on extrait les taxons (nécessaire pour savoir de qui on parle)
nb_taxons = z.cherche_taxons()
if (nb_taxons <= 0) then
return briques.t_erreur("Aucune entrée ''taxon'' fournie", "syntaxe", z.configuration) .. z.box_erreurs("oui") -- on force l'erreur
end
-- on détermine les titres et autres
z.cherche_titres(frame)
-- on parcours les lignes de structuration pour générer la sortie
for i = 1, nb_lignes do
tmp = z.traite_ligne(descriptions[i])
if (tmp == nil) then
-- erreur qui ne peut être ignorée
return briques.t_erreur("Erreur de ligne ''début'' ou ''phylogénie bandeau", "syntaxe", z.configuration) .. z.box_erreurs("oui") -- on force l'erreur
end
tx = tx .. tmp
end
-- si la taxobox n'est pas fermée on la ferme
if (fermeture_taxobox == false) then
z.traite_fin() -- fermeture implicite, rendant donc "fin" optionnel
end
-- tout c'est passé correctement, on modifie le titre/sous-titre
-- si présent, et si article, on traite le sous-titre
if (z.configuration.sous_titre == nil) then
pdebug = pdebug .. "sous_titre = <nil><br/>"
else
pdebug = pdebug .. "sous_titre = " .. z.configuration.sous_titre .. "<br/>"
end
local boite_titres = ""
if (z.configuration.sous_titre ~= nil and z.configuration.sous_titre ~= "") then
-- on détermine si la gestion du sous-titre est active
local t = false
local b = false
if (z.configuration.c_sous_titre == "non") then
t = false
elseif (z.configuration.c_sous_titre == "oui") then
t = true
else
if (z.configuration.article == true) then
t = true
else
t = false
b = true -- boîte
end
end
if (z.configuration.c_sous_titre == "boîte" or b == true) then
boite_titres = boite_titres .. "Sous-titre :<br/>" .. z.configuration.sous_titre .. "<br/>"
else
if (t == true) then
tx = tx .. briques.t_sous_titre(z.configuration.sous_titre)
end
end
else
if (z.configuration.c_sous_titre == "boîte" or (z.configuration.c_sous_titre == "auto" and z.configuration.article == false)) then
boite_titres = boite_titres .. "Sous-titre :<br/> ''aucun''<br/>"
end
end
if (z.configuration.titre_article == nil) then
pdebug = pdebug .. "titre_article = <nil><br/>"
else
pdebug = pdebug .. "titre_article = " .. z.configuration.titre_article .. "<br/>"
end
-- si présent, et si article, on traite la modification du titre
if (z.configuration.titre_article ~= nil and z.configuration.titre_article ~= "") then
-- est-ce qu'on doit modifier ?
local t = false
local b = false
if (z.configuration.c_titre == "oui") then
t = true
elseif (z.configuration.c_titre == "non") then
t = false
else -- auto
if (z.configuration.article == true) then
t = true
else
t = false
b = true -- mode boîte si auto
end
end
if (z.configuration.c_titre == "boîte" or b == true) then
boite_titres = boite_titres .. "Titre :<br/>" .. z.configuration.titre_article .. "<br/>"
else
if (t == true) then
local modif = "{{DISPLAYTITLE:" .. z.configuration.titre_article .. "}}"
tx = tx .. frame:preprocess(modif)
end
end
else
if (z.configuration.c_titre == "boîte" or (z.configuration.c_titre == "auto" and z.configuration.article == false)) then
boite_titres = boite_titres .. "Titre :<br/> ''aucun''<br/>"
end
end
-- on insert les catégories et les erreurs
tx = tx .. z.box_categories()
tx = tx .. z.box_erreurs(z.configuration.c_erreurs)
-- on insert la boîte des titres (à faire en fonction)
if (boite_titres ~= "") then
tx = tx .. briques.t_debut("", "Titre/sous-titre")
tx = tx .. "<small>" .. boite_titres .. "</small>"
tx = tx .. briques.t_end()
end
-- spécial : le mode "raw" nécessite quelques ajustements
if (z.configuration.c_raw == "oui") then
tx = tx .. "</nowiki>"
return frame:preprocess(tx)
end
if (z.configuration.c_debug == "oui") then
return data.message .. tx .. pdebug -- cette partie seulement si demandée
else
return data.message .. tx
end
end
local sup = ""
-- recupère le contenu du modèle suivant complet
function z.extrait_modele(texte, depart)
local cnt = 0
local pos = depart
local npos
local debut = nil
local fin = nil
local t
if (depart > string.len(texte)) then
return nil, nil
end
debut = string.find(texte, "{{", pos, true)
if (debut == nil) then
return nil, nil
end
cnt = 1
while (true) do
local p1 = string.find(texte, "{{", pos+2, true)
local p2 = string.find(texte, "}}", pos+2, true)
if (p2 == nil) then
return nil, nil
end
if (p1 == nil) then
cnt = cnt - 1
npos = p2+2
if (cnt == 0) then
return debut, p2+1
end
elseif (p1 < p2) then
cnt = cnt + 1
npos = p1+2
else
cnt = cnt - 1
npos = p2+2
if (cnt == 0) then
return debut, p2+1
end
end
pos = npos
end
end
-- cherche le | suivant, en ignorant ceux dans des modèles ou wikiliens
-- retourne une position (utf8)
function z.pipe_suivant(ligne, posr)
local pos = posr
local cnt = 0
while (true) do
local c = mw.ustring.sub(ligne, pos, pos)
if (c == nil or c == "") then
if (pos <= posr) then
return nil
else
return pos
end
end
-- on comptabilise les entrées/sorties de modèle/lien
if (c == "[" or c == "{") then
cnt = cnt + 1
elseif (c == "]" or c == "}") then
cnt = cnt - 1
elseif (c == "|") then
-- si | on retourne la position que si cnt = 0
if (cnt == 0) then
return pos
end
end
pos = pos + 1
end
-- on ne vient pas là
return nil
end
-- découpe selon les | et range dans une table
function z.decoupe_pipe(ligne)
local tbl = {}
local pos
local courant = 1
pos = z.pipe_suivant(ligne, 1)
if (pos == nil) then
table.insert(tbl, ligne) -- un seul élément
return tbl
end
while (pos ~= nil) do
-- on recupere de "courant" à pos
local tmp = mw.ustring.sub(ligne, courant, pos-1)
table.insert(tbl, tmp)
courant = pos + 1
-- on recupere la partie suivante
pos = z.pipe_suivant(ligne, courant)
end
return tbl
end
-- cette fonction reçoit (non processé) une taxobox et retourne la même chose
-- avec la syntaxe actuelle
function z.convertisseur(frame)
local tx = "{{user:Hexasoft/Scribunto/Taxobox\n"
local txt = [=[
{{Taxobox début | algue | une_image.jpg | légende | classification=AlgaeBASE }}
{{Taxobox | sous-règne | Hacrobia }}
{{Taxobox | sous-règne | Hacrobia (truc) | Hacrobia}}
{{Taxobox | sous-règne | Hacrobia | ancien=oui }}
{{Taxobox taxon | algue | embranchement | Haptophyta | <auteurs>, <date> }}
{{Taxobox taxon | algue | embranchement | Haptophyta | <auteurs>, <date> }}
{{Taxobox taxon | algue | embranchement | Haptophyta | <auteurs>, <date> }}
{{Taxobox taxons |
* classe ''[[Pavlovophyceae]]''
** ordre ''[[Pavlovales]]''
* classe ''[[Prymnesiophyceae]]'' Hibberd, 1976
** ordre ''[[Prymnesiales]]''
** ordre ''[[Phaeocystales]]''
** ordre ''[[coccolithophore|Isochrysidales]]''
** ordre ''[[coccolithophore|Coccolithales]]''
}}
{{taxobox synonymes |
* ''Turlu tutu'' <small>Chapeau Pointu</small> }}
{{Taxobox UICN | LC | 1Ab12-coulé | chez moi }}
{{Taxobox UICN | VU | 1Ab12-coulé | ailleurs }}
{{Taxobox position | {{Phylogénie Eukaryota}} | Cryptophyta }}
{{Taxobox fin}}
]=]
local ligne
local tbl = {}
debut, fin = z.extrait_modele(txt, 1)
if (debut == nil) then
return "''Syntaxe probablement erronée.''<br/>" .. sup
end
while (debut ~= nil) do
-- on récupère la ligne
ligne = string.sub(txt, debut+2, fin-2)
-- on découpe selon les | présents
tbl = z.decoupe_pipe(ligne)
if (tbl[1] ~= nil) then
-- on analyse le premier
local tmp = z.nettoie(string.lower(tbl[1]))
if (tmp == "taxobox début") then
-- le règne
regne = z.nettoie(tbl[2])
tx = tx .. "|règne=" .. regne .. "\n"
-- les autres parametres
tx = tx .. "|début "
local i = 3
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox phylogénie bandeau") then
tx = tx .. "|phylogénie bandeau "
local i = 2
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox") then
tx = tx .. "|rang "
local i = 2
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
local p1 = mw.ustring.match(tbl[i], "^%s*(%a*)%s*=")
if (p1 == "ancien") then
tx = tx .. "|ancien "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox fin") then
tx = tx .. "|fin\n"
elseif (tmp == "taxobox taxon") then
tx = tx .. "|taxon "
local i = 3
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
-- obsolète ou nouveau ?
local p1 = mw.ustring.match(tbl[i], "%s*(%a*)%s*=")
if (p1 == "obsolète") then
tx = tx .. "| obsolète "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox image") then
tx = tx .. "|image "
local i = 2
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
-- obsolète ou nouveau ?
local p1 = mw.ustring.match(tbl[i], "%s*(%a*)%s*=")
if (p1 == "séparateur") then
tx = tx .. "| séparateur "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox conflit") then
tx = tx .. "|conflit "
local i = 2
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox répartition début") then
tx = tx -- rien à faire car inutile
elseif (tmp == "taxobox répartition fin") then
tx = tx -- rien à faire car inutile
elseif (tmp == "taxobox répartition légende") then
tx = tx .. "|répartition légende "
local i = 2
while (tbl[i] ~= nil) do
local rr = string.find(tbl[i], "=")
if (rr == nil) then
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
else
-- on remplace le = par un |
tx = tx .. "|" .. z.nettoie(string.gsub(tbl[i], "=", "| ")) .. " "
end
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox uicn") then
tx = tx .. "|uicn "
local i = 2
while (tbl[i] ~= nil) do
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox légende") then
tx = tx .. "|légende "
local i = 2
while (tbl[i] ~= nil) do
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox parents") then
tx = tx .. "|parents "
local i = 2
while (tbl[i] ~= nil) do
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox cites") then
tx = tx .. "|cites "
local i = 2
while (tbl[i] ~= nil) do
tx = tx .. "|" .. z.nettoie(tbl[i]) .. " "
i = i + 1
end
tx = tx .. "\n"
elseif (tmp == "taxobox taxons") then
tx = tx .. "|taxons "
if (tbl[2] ~= nil) then
tx = tx .. "|" .. tbl[2] .. " "
end
if (tbl[3] ~= nil) then
tx = tx .. "|" .. tbl[3] .. " "
end
tx = tx .. "\n"
elseif (tmp == "taxobox synonymes") then
tx = tx .. "|synonymes "
if (tbl[2] ~= nil) then
tx = tx .. "|" .. tbl[2] .. " "
end
tx = tx .. "\n"
elseif (tmp == "taxobox position") then
tx = tx .. "|position "
if (tbl[2] ~= nil) then
tx = tx .. "|" .. tbl[2] .. " "
end
if (tbl[3] ~= nil) then
tx = tx .. "|" .. tbl[3] .. " "
end
tx = tx .. "\n"
else
tx = tx .. "|Élément inconnu (" .. tmp .. ")\n"
end
end
-- le suivant
cur = fin + 1
debut, fin = z.extrait_modele(txt, cur)
end
tx = tx .. "}}"
tx = "<pre>" .. txt .. "</pre>\n\n" .. "<pre>" .. tx .. "</pre>\n\n" .. tx .. "\n"
-- reste à faire : phylo arbre, phylo inexistant, répartition, répartition image
return frame:preprocess(tx)
end
-- cette fonction génère une erreur d'exécution
function z.fonction_en_erreur(frame)
local t = string.find(nil, nil)
end
function z.mw_title(frame)
res = ""
-- afficher le contenu de mw.title
for k, v in pairs( mw.title ) do
res = res .. "mw.title: " .. k .. " → " .. type(v) .. "<br/>\n"
end
return res
end
return z