Module:Liste des corrections

La documentation pour ce module peut être créée à Module:Liste des corrections/Documentation

local p = {}

-- Dresse la liste des corrections apportées dans un livre
function p.liste (frame)
	local args = frame.args
	local index = args[1]
	local section = "correction" -- nom de la section, par défaut celui du modèle {{Page Discussion}}
	local total = 0 -- nombre total de corrections
	local out = mw.html.create()
	local corrections = mw.html.create( 'table' )
	local NS = "Discussion_Page" -- par défaut les explications sont sur les pages de discussion de l'espace Page
	
	if not index or index == "" then
		return "Le nom du livre n’a pas été donné."	
	end
	
	-- on change le nom de la section des corrections si besoin
	if args[2] ~= nil and args[2] ~= "" then
		section = args[2]	
	end
	
	-- si on souhaite récupérer la liste des corrections
	-- directement avec le modèle {{corr}}
	if args.avec ~= nil and args.avec == "corr" then
		NS = "Page"
	end
	
	local l = mw.title.new(index, "Media")
	if l.exists then
		local pagelist = p.get_pagelist(index)
		local npages = #l.file.pages
		if npages then
			local i=1 -- page du fichier
			local n=1 -- page en fonction du décalage
			local nt= nil
			local pn = nil
			local page = nil
			
			while (i<=npages) do
				pn = pagelist["p"][tostring(i)]
				if pn ~= nil then
					if tonumber(pn) ~= nil then
						n = tonumber(pn)
						nt=n
					else 
						nt = pn
					end
				else
					nt=n
				end
				
				for _, r in ipairs( pagelist["r"] ) do
					if i>= r[1] and i<=r[2] then
						nt=p.int2roman(n)
					end
				end
				
				page = mw.title.new(index.."/"..i, NS)
				local content = page:getContent()
				-- BUG limite 500 appels (cf Sujet:Unmn96gkz9zox8uh)
				-- NE PAS UTILISER page.exists ci dessous, cette fonction coûteuse
				-- incrémente $wgExpensiveParserFunctionLimit et bloque le script à la 501ème page
				-- au lieu de cela, on teste si son contenu est différent de nil (la page n'existe pas) ou vide
				-- problème : la page est enregistrée comme une transclusion
				if content ~= nil and content ~="" then
					local corr = nil
					if NS == "Page" then
						corr = p.get_corr(content)
					else
						corr = frame:callParserFunction{ 
							name = '#lst:'..page.fullText , 
							args = { section } 
						}
					end
					
					if (corr ~= "" and corr ~= nil) then
						local tr =  mw.html.create( 'tr' )
						local td_page = mw.html.create( 'td' )
						local td_corr = mw.html.create( 'td' )
						local expl_txt = ""
						
						if NS == "Page" then
							-- on cherche si {{CorrBandeau}} est utilisé dans la page
							local explications = string.find(content, "{{[Cc]orrBandeau}}")
							if explications == nil then 
								-- on cherche si {{CorrDiscussion}} est utilisé dans la page de discussion
								page_d = mw.title.new(index.."/"..i, "Discussion_Page")
								content_d = page_d:getContent()
								if content_d ~= nil then
									explications = string.find(content_d, "{{[Cc]orrDiscussion")
								end
							end
							if explications ~= nil then 
								expl_txt = ' <sup>([[Discussion_Page:'..page.text..'|expl.]])</sup>'
							end
						end
						
						td_page:wikitext("'''Page [["..page.fullText.."|"..nt.."]]'''"..expl_txt.." :")
						       :css("padding","0.5em 0.5em 0 0")
						       :css("white-space","nowrap")
						
						if NS == "Page" then
							if corr == false then
								corr = frame:expandTemplate{ 
									title = 'rouge' , 
									args = { frame:preprocess('Une erreur avec un modèle {{m|corr}} a été détectée sur cette page.') } 
								}
								td_corr:wikitext(corr)
							else
								for _, c in ipairs(corr) do
										-- le deuxième argument peut contenir du wikicode
										local cm = frame:expandTemplate{ 
											title = 'CorrDiscussion' , 
											args = { c[1], frame:preprocess(c[2]), nombre=c[3] } 
										}
									td_corr:node(cm)
								end
							end
						else
							td_corr:wikitext(corr)
						end
						
						tr:node(td_page):node(td_corr)
						  :css("vertical-align","top")
						corrections:node(tr)
						total = total +1
					end
				end
				i = i+1
				n = n+1
			end
			
			if total > 0 then
				if next(pagelist["p"]) ~= nil then
					out:wikitext("''Les informations relatives aux pages (numéro, libellé) correspondent à ceux de la balise <pagelist/> provenant de [[Index:"..index.."|l’index]].''")
				else
					out:wikitext("''Les numéros de page correspondent à ceux du fichier.''")
				end
				if NS == "Page" then
					local mc = frame:expandTemplate{ title = 'm', args = {'corr'} }
					out:wikitext("<br/>''La liste des corrections est dressée à partir des modèles "..mc.." utilisés.''")
				end
				out:node(corrections)
				return out 
			else
				return "''Aucune correction n’a été apportée à ce livre."
			end
		end
	else
		return "Le livre « [[Livre:"..index.."|"..index.."]] » n’existe pas."	
	end
	
end

-- Récupère les différents <pagelist/> sur la page d'index
-- @param index string : nom de l'index sans le préfixe
-- @return array : tableau contenant les décalages (9=3) et libellés (2=TdM) des différents <pagelist/> 
function p.get_pagelist(index)
	local page = mw.title.new(index, "Index")
	local content = page:getContent()
	local pages = {}
	local roman={}
	for pl in string.gmatch(content, "<pagelist[^>]+/>") do 
		-- récupère et stocke la valeur la page (9=3, 2=Tdm,...)
		for pi,pv in string.gmatch(pl, "%s([1-9][0-9]*)=([^%s/]+)") do
			pages[pi]=mw.text.trim( pv, '"' ) -- enlève les "" en début et fin de chaine
		end
		-- récupère les pages devant apparaître comme des nombres romains
		for fr,to in string.gmatch(pl, "([1-9][0-9]*)to([1-9][0-9]*)=roman") do
			table.insert( roman, {tonumber(fr),tonumber(to)} ) 
		end
	end
	return {["p"]=pages,["r"]=roman}
end

-- Récupère tous les modèles {{corr}} sur une page.
-- Attention, le deuxième argument du modèle corr peut contenir un autre modèle
-- @param c string : contenu de la page
-- @return array|nil : tableau contenant les valeurs des corr, nil si aucun corr
function p.get_corr(c)
	local corr = {}
	local init= 1
	while true do
		p_start,p_end = mw.ustring.find(c, "{{[Cc]orr%|", init)
		-- si le motif n'est plus dans la chaine on stop la recherche
		if p_start == nil then break end
		-- on récupère ce qui est après le motif
		local after_p = mw.ustring.sub(c, p_end+1)
		-- on recherche la fin réelle du modèle
		-- correspond à 0 par addition et soustraction de { et }
		local corr_i = 2; -- les deux déjà dans le motif
		local corr_args = nil
		for i = 1, #after_p do
		    local char = mw.ustring.sub(after_p,i,i)
		    if char == "{" then 
		    	corr_i = corr_i+1
		    elseif char == "}" then
		    	corr_i = corr_i-1
		    end
		    if corr_i == 0 then
		    	corr_args = mw.ustring.sub(after_p,1,i-2)
		    	break
		    end
		end
		
		if corr_args ~= nil then
	    	local fist_pipe_pos = mw.ustring.find(corr_args, "|", 1, true)
	    	if fist_pipe_pos ~= nil then
		    	local corr_arg1 = mw.ustring.sub(corr_args,1,fist_pipe_pos-1)
		    	local corr_arg2 = mw.ustring.sub(corr_args,fist_pipe_pos+1)
		    	-- si la correction est multiple on ne la stocke qu'une fois
				local m = false
				for i, v in ipairs(corr) do
					if corr_arg1==v[1] and corr_arg2==v[2] then
						corr[i][3] = v[3]+1
						m=true
					end
				end
				if not m then
					table.insert(corr, {corr_arg1, corr_arg2, 1})
				end
			else
				return false -- erreur
			end
	    end
		init = p_end -- reprend la recherche à la fin du motif
	end
	if #corr == 0 then return nil else return corr end
end

-- Transforme un entier (5) en nombre romain minuscule (v)
-- honteusement copié de https://www.rosettacode.org/wiki/Roman_numerals/Encode#Lua
-- Module:MathRoman ne semble pas fonctionner
-- @param s integer|string : entier à transformer
-- @return string : nombre romain
function p.int2roman(s)
    romans = {
		{1000, "M"},
		{900, "CM"}, {500, "D"}, {400, "CD"}, {100, "C"},
		{90, "XC"}, {50, "L"}, {40, "XL"}, {10, "X"},
		{9, "IX"}, {5, "V"}, {4, "IV"}, {1, "I"} 
    }

	s = tonumber(s) -- donne nil si s n'est pas un nombre
	if not s then return s end -- renvoit nil
	
	out = ""
	for _, v in ipairs(romans) do --note that this is -not- ipairs.
	  val, let = unpack(v)
	  while s >= val do
	    s = s - val
		out = out .. let
	  end
	end
	return string.lower(out)
end

return p