Module:Taxobox2
Apparence
La documentation pour ce module peut être créée à Module:Taxobox2/doc
--[[
Module créant une taxobox.
Utilise Module:Taxobox données et Module:Taxobox fonctions.
Note : le nom est temporaire. Module:Taxobox existe et contient une vieille version destinée à être remplacée.
--]]
-- la table du module
local p = {}
local donnees = require "Module:Taxobox données"
local fnc = require "Module:Taxobox fonctions"
--[[
Fonction générant la sortie finale. Permet d'inclure le debug éventuel
--]]
function p.prepare_sortie(contenu, db)
if (donnees.defauts.c_debug) then
return db .. donnees.defauts.frame:preprocess(contenu)
else
return donnees.defauts.frame:preprocess(contenu)
end
end
--[[
Fonction principale : traite les paramètres et génère la taxobox.
Les paramètres sont :
règne : obligatoire. Sélectionne le thème (couleur, convention typographique, lignes de classification)
nom vernaculaire : facultatif. Informe la taxobox du ou des noms vernaculaires existants
…
--]]
function p.taxobox(frame)
local dg = ""
donnees.defauts.frame = frame -- pour que les fonctions aient accès à la frame courante simplement
donnees.defauts.pframe = frame:getParent() -- pour que les fonctions aient accès à la frame courante simplement
dg = dg .. "frames préparées.<br/>"
-- on récupère les infos sur l'article où on se trouve
local curarticle = mw.title.getCurrentTitle()
if (curarticle.namespace == 0) then -- est-ce un article ou pas
donnees.defauts.article = true
else
donnees.defauts.article = false
end
-- le titre courant
donnees.defauts.titre = curarticle.text
dg = dg .. "namespaces+titre extraits.<br/>"
-- récupération des paramètres
donnees.defauts.regne = fnc.lit_parametre("charte", donnees.regnes, false, nil) -- la charte
if (donnees.defauts.regne == nil) then -- on teste charte, puis règne si marche pas
donnees.defauts.regne = fnc.lit_parametre("règne", donnees.regnes, false, true) -- le règne
end
donnees.defauts.nom_vernaculaire = fnc.lit_parametre("nom vernaculaire", nil, false, nil) -- le non vernaculaire
-- les options permettant de modifier le comportement
donnees.defauts.c_titre = fnc.lit_parametre("titre", {"oui","non","boîte","auto"}, false, "auto")
donnees.defauts.c_sous_titre = fnc.lit_parametre("sous-titre", {"oui","non","auto"}, false, "auto")
donnees.defauts.c_erreurs = fnc.lit_parametre("erreurs", {"oui","non","auto"}, false, "auto")
donnees.defauts.c_categories = fnc.lit_parametre("catégories", {"en ligne","non","boîte","auto"}, false, "auto")
donnees.defauts.c_err_categories = fnc.lit_parametre("catégorie erreurs", {"en ligne","non","boîte","auto"}, false, "auto")
donnees.defauts.c_force_titre = fnc.lit_parametre("force titre", nil, false, nil)
-- si force titre vide on utilise le titre réel
if (donnees.defauts.c_force_titre == nil) then
donnees.defauts.c_force_titre = donnees.defauts.titre
end
-- debug
donnees.defauts.c_raw = fnc.lit_parametre("raw", nil, true, nil)
donnees.defauts.c_debug = fnc.lit_parametre("debug", nil, true, nil)
-- on regarde si une erreur (ou plusieurs) s'est produite durant la récupération des paramètres
if (donnees.defauts.fatal) then
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg)
end
dg = dg .. "paramètres récupérés.<br/>"
-- on récupère la structure règne
donnees.defauts.regne_data = donnees.regnes[donnees.defauts.regne]
if (donnees.defauts.regne_data == nil) then
fnc.erreur_normale("Le règne indiqué ''" .. donnees.defauts.regne .. "'' n'est pas reconnu.", "syntaxe")
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg)
end
-- on analyse les paramètres pour générer la liste des commandes présentes
local xxx, yyy = fnc.tri_parametres(donnees)
dg = dg .. yyy
if (donnees.defauts.fatal) then -- erreur → fatal
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg)
end
dg = dg .. "commandes analysées.<br/>"
local w = 1
while (donnees.defauts.commandes[w] ~= nil) do
local ww = 1
while (donnees.defauts.commandes[w][ww] ~= nil) do
dg = dg .. donnees.defauts.commandes[w][ww] .. " "
ww = ww + 1
end
dg = dg .. "<br/>"
w = w + 1
end
dg = dg .. "EOC<br/>"
-- initialisation de l'état de la taxobox en construction
donnees.etat = {}
donnees.etat.ouvert = false -- la taxobox est commencée
donnees.etat.ferme = false -- la taxobox est terminée
donnees.etat.ligne = "non commencé" -- le nom de la ligne en cours
donnees.etat.tbl = 0 -- nombre de tables ouvertes
dg = dg .. "état taxobox initialisé.<br/>"
-- on parcours les commandes pour trouver les "taxon", afin de valider leur présence
-- et de trouver le titre de la taxobox
fnc.tri_taxons()
if (donnees.defauts.fatal) then -- erreur → fatal
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg)
end
dg = dg .. "taxons analyés (dernier taxon et titre = " .. donnees.defauts.titre_taxobox .. ").<br/>"
-- on traite le titre/sous-titre : est-ce le NS ? Est-ce le NV ? Autre ?
fnc.genere_titre_taxobox()
dg = dg .. "titre taxobox géré (titre = " .. donnees.defauts.titre_taxobox .. ").<br/>"
-- parcours des commandes et appel des fonctions de traitement de chaque ligne
local tb = ""
local i = 1
local courant = ""
local precedent = ""
while (donnees.defauts.commandes[i] ~= nil) do
-- le mot-clé
local cle = donnees.defauts.commandes[i][1]
if (cle == nil) then -- fatal
fnc.erreur_fatale("La " .. i .. "ème commande n'existe pas.", "interne")
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg)
end
courant = cle
dg = dg .. " - commande : " .. cle .. "<br/>"
-- on récupère le descriptif de cette commande
local cmd = fnc.syntaxe[cle]
if (cmd == nil) then
dg = dg .. " -> commande non référencée<br/>"
fnc.erreur_fatale("La " .. i .. "ème commande (''" .. cle .. "'') n'est pas référencée dans les actions.", "interne")
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg)
end
dg = dg .. " -> cmd : " .. type(cmd[1]) .. ", " .. type(cmd[2]) .. ", " .. type(cmd[3]) .. "<br/>"
-- si pas de fonction associée erreur non fatale et on ignore
if (cmd[3] == nil) then
dg = dg .. " -> commande non implémentée<br/>"
fnc.erreur_normale("La commande ''" .. cle .. "'' n'est pas encore implémentée.", "interne")
else
-- on analyse la ligne
local etat, resu = pcall(fnc.lecture_parametres, donnees.defauts.commandes[i], 2, cmd[2])
if (not etat) then
fnc.erreur_fatale("Échec d'appel à lecture_parametres (" .. cle .. ") (" .. resu .. ").", "interne")
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg) -- on quitte
end
-- on ajoute le nom de la commande réelle (pour les commandes différentes qui utilisent la même fonction)
resu["commande"] = cle
dg = dg .. " - syntaxe analysée<br/>"
-- gestion des erreurs
if (resu == nil or resu.erreurs ~= nil) then
-- une erreur sur cette ligne est-elle fatale ?
dg = dg .. " -> commande retourne une erreur<br/>"
if (cmd[1] == 2) then
fnc.erreur_fatale((resu.erreurs or "non précisé"), "syntaxe")
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg) -- on quitte
else
fnc.erreur_normale((resu.erreurs or "non précisé"), "syntaxe")
end
else
dg = dg .. " - syntaxe validée<br/>"
-- on exécute la ligne
local tmpr, tmpd
tmpr, tmpd = pcall(cmd[3], resu)
if (not tmpr) then
fnc.erreur_fatale("Échec d'appel à la fonction de gestion de ''" .. cle .. "'' (" .. tmpd .. ").", "interne")
return p.prepare_sortie(fnc.erreur_globale(donnees.defauts, donnees.categorie_erreur), dg) -- on quitte
end
dg = dg .. "données : precedent=" .. precedent .. ", courant=" .. courant .. ", tbl=" .. donnees.etat.tbl .. "<br/>"
-- gestion des fermetures de tables
if (courant ~= "rang" and courant ~= "conflit" and (precedent == "rang" or precedent == "conflit")) then
tb = tb .. "</table>"
donnees.etat.tbl = donnees.etat.tbl - 1
end
-- cas particulier : on sort de début sans ligne de classification ensuite
if (donnees.etat.tbl > 0 and courant ~= "rang" and courant ~= "conflit" and precedent == "début") then
dg = dg .. "tbl>0 (" .. donnees.etat.tbl .. "), courant ~= rang,conflit (" .. courant .. ")<br/>"
-- on quitte un rang → on ferme la table
tb = tb .. "</table>"
donnees.etat.tbl = donnees.etat.tbl - 1
end
-- traitement de "dépannage" : si "rang" sans table ouverte on ouvre la table mais c'est une erreur
if ((courant == "rang" or courant == "conflit") and donnees.etat.tbl <= 0) then
fnc.erreur_normale("Ligne " .. i .. " : commande ''rang'' en dehors d'une zone adéquate.", "syntaxe")
tb = tb .. '<table class="taxobox_classification taxoalternance"><caption>Erreur</caption>\n'
donnees.etat.tbl = donnees.etat.tbl + 1
end
-- on insert l'élément
tb = tb .. tmpd
dg = dg .. " - commande traitée<br/>"
end
end
-- on bascule courant/precedent
precedent = courant
-- ligne suivante
i = i + 1
end
-- ici il faut valider que la taxobox est terminée proprement
if (donnees.etat.tbl >= 1) then
-- on ferme les tables
for i = 1, donnees.etat.tbl do
tb = tb .. "</table>"
end
donnees.etat.tbl = 0
end
-- fermeture
if (donnees.etat.ferme == false) then
tb = tb .. "</div>"
donnees.etat.ferme = true
end
-- traitement titre article (mise en forme si nécessaire)
local mtitre = ""
if (donnees.defauts.taxon_titre ~= nil) then -- il y a un titre NS
if (donnees.defauts.c_titre ~= "non") then
dg =dg .. "titre a modifier a priori : titre = " .. donnees.defauts.c_force_titre .. ", ciblé = " .. donnees.defauts.commandes[donnees.defauts.taxon_titre][3] .. "<br/>"
-- le titre modifié
local tmp = fnc.italiques_titre(donnees.defauts.c_force_titre, donnees.defauts.commandes[donnees.defauts.taxon_titre][3], donnees.defauts.commandes[donnees.defauts.taxon_titre][2])
dg = dg .. " -> " .. tmp .. "<br/>"
-- selon le mode
if (donnees.defauts.c_titre == "boîte" or (donnees.defauts.c_titre == "auto" and not donnees.defauts.article)) then
mtitre = mtitre .. fnc.box_ouverture("Titre")
mtitre = mtitre .. fnc.box_texte(frame:preprocess("<nowiki>" .. tmp .. "</nowiki>"))
mtitre = mtitre .. fnc.box_fermeture()
elseif (donnees.defauts.c_titre == "oui" or (donnees.defauts.c_titre == "auto" and donnees.defauts.article)) then
mtitre = mtitre .. frame:preprocess(tmp)
end
end
end
-- traitement sous-titre éventuel
local mstitre = ""
if (donnees.defauts.c_sous_titre ~= "non") then
dg = dg .. "sous-titre potentiel<br/>"
local sst = nil
-- si taxon_titre → titre en NS, on ajoute le NV si présent
if (donnees.defauts.taxon_titre ~= nil) then
dg = dg .. " -> vernaculaire : " .. (donnees.defauts.nom_vernaculaire or "non défini") .. "<br/>"
sst = donnees.defauts.nom_vernaculaire
else
-- titre NV, on ajoute le NS en sous-titre
dg = dg .. " -> scientifique : " .. donnees.defauts.titre_taxobox .. "<br/>"
sst = donnees.defauts.titre_taxobox
end
if (donnees.defauts.c_sous_titre == "boîte" or (donnees.defauts.c_sous_titre == "auto" and not donnees.defauts.article)) then
if (sst ~= nil) then
mstitre = mstitre .. fnc.box_ouverture("Sous-titre")
mstitre = mstitre .. fnc.box_texte(sst)
mstitre = mstitre .. fnc.box_fermeture()
end
elseif (donnees.defauts.c_sous_titre == "oui" or (donnees.defauts.c_sous_titre == "auto" and donnees.defauts.article)) then
-- on l'insert en tant que sous-titre
if (sst ~= nil) then
mstitre = mstitre .. '<span id="sous_titre_h1">' .. sst .. '</span>'
end
end
end
-- si besoin et selon les modalités on insert les catégories
local mcat = ""
if (donnees.defauts.r_categories[1] ~= nil and donnees.defauts.c_categories ~= "non") then
-- selon le mode
if (donnees.defauts.c_categories == "boîte" or (donnees.defauts.c_categories == "auto" and donnees.defauts.article == false)) then
mcat = mcat .. fnc.box_ouverture("Catégorie(s)")
mcat = mcat .. fnc.box_texte(donnees.defauts.r_categories, true)
mcat = mcat .. fnc.box_fermeture()
elseif (donnees.defauts.c_categories == "en ligne" or (donnees.defauts.c_categories == "auto" and donnees.defauts.article == true)) then
-- insertion "en vrai"
local i = 1
while (donnees.defauts.r_categories[i] ~= nil) do
mcat = mcat .. "[[Catégorie:" .. donnees.defauts.r_categories[i] .. "]]"
i = i + 1
end
end
end
-- si besoin et selon les modalités on insert les catégories d'erreur
local mcaterr = ""
if (donnees.defauts.r_err_categories[1] ~= nil and donnees.defauts.c_err_categories ~= "non") then
dg = dg .. "Il y a des catégories d'erreur<br/>"
-- selon le mode
if (donnees.defauts.c_err_categories == "boîte" or (donnees.defauts.c_err_categories == "auto" and donnees.defauts.article == false)) then
mcaterr = mcaterr .. fnc.box_ouverture("Catégorie d'erreur(s)")
mcaterr = mcaterr .. fnc.box_texte(donnees.defauts.r_err_categories, true)
mcaterr = mcaterr .. fnc.box_fermeture()
elseif (donnees.defauts.c_err_categories == "en ligne" or (donnees.defauts.c_err_categories == "auto" and donnees.defauts.article == true)) then
-- insertion "en vrai"
local i = 1
while (donnees.defauts.r_err_categories[i] ~= nil) do
mcat = mcat .. "[[Catégorie:" .. donnees.categorie_erreur .. "|" .. donnees.defauts.r_categories[i] .. "]]"
i = i + 1
end
end
end
-- si besoin et selon les modalités on insert les erreurs
local merr = ""
if (donnees.defauts.r_erreurs[1] ~= nil and donnees.defauts.c_erreurs ~= "non") then
-- selon le mode
if (donnees.defauts.c_erreurs == "boîte" or (donnees.defauts.c_erreurs == "auto" and donnees.defauts.article == false)) then
merr = merr .. fnc.box_ouverture("Erreur(s)")
merr = merr .. fnc.box_texte(donnees.defauts.r_erreurs)
merr = merr .. fnc.box_fermeture()
end
end
-- terminé, on retourne le tout
return p.prepare_sortie(tb .. mtitre .. mstitre .. mcat .. mcaterr .. merr, dg)
end
-- cherche le | suivant, en ignorant ceux dans des modèles ou wikiliens
-- retourne une position (utf8)
function p.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 p.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 = p.pipe_suivant(ligne, courant)
end
return tbl
end
--[[
Découpe un modèle en ses paramètres
--]]
function p.decoupe_modele(modele)
end
--[[
Prend en paramètre un modèle modulaire, et retourne sa version monolytique
--]]
function p.mono_vers_modu(modele)
return ""
end
-- on retourne le module
return p