Module:Taxobox-fr
Documentation for this module may be created at Module:Taxobox-fr/doc
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 .. "[[Category:" .. p1 .. "]]"
else
ret = ret .. "[[Category:" .. p1 .. "|" .. p2 .. "]]"
end
else
if (p2 == nil) then
ret = ret .. "[[:Category:" .. p1 .. "|" .. p1 .. "]]<br/>"
else
ret = ret .. "[[:Category:" .. 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
-- -- 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")
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")
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")
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")
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")
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")
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.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
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
-- 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.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.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.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
-- découpe selon les | et range dans une table
function z.decoupe_pipe(ligne)
local tbl = {}
local pos
local courant = 1
pos = string.find(ligne, "|", courant, true)
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 = string.sub(ligne, courant, pos-1)
table.insert(tbl, tmp)
courant = pos + 1
-- on recupere la partie suivante
pos = string.find(ligne, "|", courant, true)
end
-- on récupère le dernie morceau
local tmp = string.sub(ligne, courant, -1)
table.insert(tbl, tmp)
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 = "<pre>{{Taxobox-fr\n"
local txt = [=[
{{Taxobox début | algue | image.png | légende | classification=AlgaeBASE }}
{{Taxobox | sous-règne | Hacrobia }}
{{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 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") then
tx = tx .. "|rang|...\n"
elseif (tmp == "taxobox fin") then
tx = tx .. "|fin\n"
elseif (tmp == "taxobox taxon") then
tx = tx .. "|taxon|...\n"
elseif (tmp == "taxobox taxons") then
tx = tx .. "|taxons|...\n"
elseif (tmp == "taxobox position") then
tx = tx .. "|position|...\n"
else
return "Élément inconnu : " .. tmp .. "."
end
end
-- le suivant
cur = fin + 1
debut, fin = z.extrait_modele(txt, cur)
end
tx = tx .. "}}</pre>"
return frame:preprocess(tx)
end
-- fonction pour tester le comportement sur réception de chaînes incluant des tags
function z.tags(frame)
local res = "Résultats :<br/>"
local texte = mw.clone(frame.args[1])
if (texte == nil or texte == "") then
return res .. "Pas de données d'entrée.<br/>"
end
-- on insert la chaîne brute
res = res .. "Version brute : >>" .. texte .. "<<<br/>"
-- on regarde les longueurs
res = res .. "Longueurs base + utf8 : " .. string.len(texte) .. " " .. mw.ustring.len(texte) .. "<br/>"
local txt2 = string.gsub(texte, "tag", "XXX")
local utxt2 = mw.ustring.gsub(texte, "tag", "XXX")
res = res .. "Remplacé : >>" .. txt2 .. "<< >>" .. utxt2 .. "<<<br/>"
local pos = string.find(texte, "\127")
res = res .. "ESC : " .. (pos or "<not found>") .. "<br/>"
local buf = string.gsub(texte, "\127", "_")
res = res .. "Flat : >>" .. buf .. "<< (" .. string.len(buf) .. ")<br/>"
-- on tente de tout casser
local tmp = string.gsub(texte, "\127", "_")
local part = string.match(tmp, "(....)-nowiki")
local v = tonumber(part, 16)
local ret = string.format("%04x", v+8)
local rrr = string.format("%6.4f", 3.14)
-- je bidouille le contenu
local tmp2 = string.gsub(tmp, part, ret)
-- on reforme le tag
tmp2 = string.gsub(tmp2, "_", "\127")
res = res .. "Kill : >>" .. tmp .. "<< (" .. string.len(tmp) .. ") --- " .. part .. "," .. ret .. "<br/>"
res = res .. "Attention : >>" .. tmp2 .. "<< <br/>"
return res
end
return z