Module:Infobox : Différence entre versions

De Lagny-sur-Marne Wiki
Aller à : navigation, rechercher
(ajout d'un paramètre "plurallabel" pour adapter les libellés au nombre de valeurs Wikidata, correction du rétrolien lorsque le modèle et le module n'ont pas le même nom, possibilité de passer des fonctions comme block de l'infobox)
(+ passage de marker et default_zoom)
 
(49 révisions intermédiaires par 8 utilisateurs non affichées)
Ligne 1 : Ligne 1 :
 
local p = {}
 
local p = {}
 +
local lang = 'fr'
  
-- variables globales alimentées par les paramètres utilisés
+
local item = nil -- l'élément Wikidata lié
item = nil -- l'élément Wikidata lié
+
local localdata = {}-- données concernant les paramètres passés au modèle
moduledata = nil -- la sous-page de module:Infobox demandée
+
local page = { -- données concernant la page où est affichée l'infobox
localdata = {}-- données concernant les paramètres passés au modèle
 
maincolor = '#E1E1E1'
 
page = { -- données concernant la page où est affichée l'infobox
 
 
name = mw.title.getCurrentTitle().prefixedText,
 
name = mw.title.getCurrentTitle().prefixedText,
 
namespace =  mw.title.getCurrentTitle().namespace
 
namespace =  mw.title.getCurrentTitle().namespace
 
}
 
}
 
+
local maincolor, secondcolor, thirdcolor = '#E1E1E1', '#E1E1E1', '#000000'
 
-- l'objet principal à retournerp
 
-- l'objet principal à retournerp
 
local infobox = mw.html.create('div')
 
local infobox = mw.html.create('div')
Ligne 18 : Ligne 16 :
 
local externaltext = '' -- par exemple coordonnées en titre
 
local externaltext = '' -- par exemple coordonnées en titre
 
-- modules importés
 
-- modules importés
local wikidata = require('Module:Wikidata')
+
local wikidata = require('Module:Interface Wikidata').fromLua
local defaultstyle = require('Module:Infobox/Style')
+
local valueexpl = wikidata.translate("activate-query")
local mapmod = require('Module:Carte')
+
local linguistic = require "Module:Linguistique"
 +
local wd = require 'Module:Wikidata'
 +
local mapmod = require "Module:Carte"
  
 
local i18n = {
 
local i18n = {
Ligne 33 : Ligne 33 :
  
 
local function addwikidatacat(prop)
 
local function addwikidatacat(prop)
maintenance = maintenance .. '[[Category:' .. i18n['tracking cat'] .. '/' .. string.upper(prop) .. ']]'
+
maintenance = maintenance .. wikidata.addtrackingcat(prop)
 
end
 
end
  
Ligne 39 : Ligne 39 :
 
local value, number -- valeur à retourner, nombre de valeurs pour accorder le libellé
 
local value, number -- valeur à retourner, nombre de valeurs pour accorder le libellé
 
if not query.entity then
 
if not query.entity then
query.entity = item
+
query.entity = localdata.item
 
end
 
end
 
if not query.conjtype then
 
if not query.conjtype then
Ligne 46 : Ligne 46 :
 
local claims = wikidata.getClaims(query)
 
local claims = wikidata.getClaims(query)
 
if (not claims) then
 
if (not claims) then
return
+
return nil
elseif #claims == 1 then
 
number = 'singular'
 
else
 
number = 'plural'
 
 
end
 
end
value = wikidata.formatAndCat(query)
+
return wikidata.formatAndCat(query), #claims -- pour l'accord au pluriel
return value, number
 
 
end
 
end
  
 
local function getWikidataValue(params, wikidataparam)
 
local function getWikidataValue(params, wikidataparam)
 
-- Récupère la valeur Wikidata pour la valeur, soit dans le paramètre "wikidata" soit dans le praramètre "property"
 
-- Récupère la valeur Wikidata pour la valeur, soit dans le paramètre "wikidata" soit dans le praramètre "property"
if not item then
+
if not localdata.item then
 
return nil
 
return nil
 
end
 
end
local value, number
+
local v, valnum -- la valeur à retourner, et le nombre de de valeurs (pour l'accord grammatical)
 
 
 
if not wikidataparam then -- par défaut la valeur wikidata est dans le paramètre "wikidata" mais dans les structures composées comme "title", il y a plusieurs paramètres wikidata
 
if not wikidataparam then -- par défaut la valeur wikidata est dans le paramètre "wikidata" mais dans les structures composées comme "title", il y a plusieurs paramètres wikidata
Ligne 69 : Ligne 64 :
 
if params[wikidataparam] then
 
if params[wikidataparam] then
 
if type(params[wikidataparam]) == 'function' then
 
if type(params[wikidataparam]) == 'function' then
return params[wikidataparam](item)
+
v, valnum = params[wikidataparam](localdata.item)
 
elseif type(params[wikidataparam]) == 'table' then
 
elseif type(params[wikidataparam]) == 'table' then
return expandquery(params[wikidataparam])
+
v, valnum = expandquery(params[wikidataparam])
 
else
 
else
return params[wikidataparam]
+
v, valnum = params[wikidataparam]
 
end
 
end
 
end
 
end
 +
if not v then
 +
return nil
 +
end
 +
v = linguistic.ucfirst(v)
 +
return v, valnum
 
end
 
end
  
Ligne 82 : Ligne 82 :
 
return localdata[val]
 
return localdata[val]
 
elseif type(val) == 'function' then
 
elseif type(val) == 'function' then
return val(localdata, item, params)
+
return val(localdata, localdata.item, params)
 
elseif type(val) == 'table' then
 
elseif type(val) == 'table' then
 
for i, j in pairs(val) do -- si plusieurs paramètres possibles (legacy de vieux code), prendre le preimeir non bide
 
for i, j in pairs(val) do -- si plusieurs paramètres possibles (legacy de vieux code), prendre le preimeir non bide
Ligne 99 : Ligne 99 :
 
maintenance = maintenance .. '[[Category:' .. cat .. '|' .. (sortkey or page.name) .. ']]'
 
maintenance = maintenance .. '[[Category:' .. cat .. '|' .. (sortkey or page.name) .. ']]'
 
end
 
end
 +
end
 +
 +
function p.separator(params)
 +
local style = params['separator style'] or {}
 +
style.height = style.height or '2px'
 +
style['background-color'] = style['background-color'] or maincolor
 +
 +
return mw.html.create('hr'):css( style )
 
end
 
end
  
Ligne 115 : Ligne 123 :
 
-- overwrites with those provided in the module
 
-- overwrites with those provided in the module
 
local style = {}
 
local style = {}
if maincolor then
+
style['background-color'] = maincolor
style['background-color'] = maincolor
+
style['color'] = thirdcolor
end
 
 
if params.style then
 
if params.style then
 
for i, j in pairs(params.style) do
 
for i, j in pairs(params.style) do
Ligne 133 : Ligne 140 :
  
 
function p.buildnavbox(params)
 
function p.buildnavbox(params)
 +
 +
-- définition du style
 
local class = "overflow nav " .. (params.class or '')
 
local class = "overflow nav " .. (params.class or '')
local style = params.style or {['border-width'] = '1px'}
+
local style = params.style or {}
if not style['border-color'] then
+
 
style['border-color'] = maincolor
+
if params.separated then -- options pour ajouter une ligne de séparation au dessus
 +
class = class .. ' bordered'
 +
style['border-top'] = '1px solid' .. maincolor
 
end
 
end
local previousval = localdata[params.previousparameter] or getWikidataValue(params, 'previouswikidata')
+
 
if not previousval and params['previousproperty'] then
+
-- ajustement des paramètres de données
previousval = wikidata.formatAndCat{entity = item, property = params['previousproperty']}
+
params.previousval = params.previousval or params.previousparameter -- nom de paramètre obsolète
 +
params.nextval = params.nextval or params.nextparameter
 +
 +
if params.previousproperty then
 +
params.previouswikidata = {property = params.previousproperty}
 
end
 
end
local nextval = localdata[params.nextparameter] or getWikidataValue(params, 'nextwikidata')
+
if params.nextproperty then
if not nextval and params['nextproperty'] then
+
params.nextwikidata = {property = params.nextproperty}
nextval = wikidata.formatAndCat{entity = item, property = params['nextproperty']}
 
 
end
 
end
local navbox =
+
mw.html.create('p')
+
 
 +
local previousval = getvalue(params.previousval, params) or getWikidataValue(params, 'previouswikidata')
 +
local nextval = getvalue(params.nextval, params) or getWikidataValue(params, 'nextwikidata')
 +
 +
local navbox
 +
if params.inner then -- pour celles qui sont à l'intérieur d'une table
 +
navbox = mw.html.create('tr'):tag('th'):attr('colspan', 2)
 +
style['font-weight'] = style['font-weight'] or 'normal'
 +
else
 +
navbox = mw.html.create('div')
 +
end
 +
 +
navbox
 
:addClass(class)
 
:addClass(class)
 
:css(style)
 
:css(style)
:tag('span')
+
:tag('div')
 
:addClass('prev_bloc')
 
:addClass('prev_bloc')
 
:wikitext(previousval)
 
:wikitext(previousval)
 
:done()
 
:done()
:tag('span')
+
:tag('div')
 
:addClass('next_bloc')
 
:addClass('next_bloc')
 
:wikitext(nextval)
 
:wikitext(nextval)
 
:done()
 
:done()
:done()
+
:allDone()
return navbox
+
return navbox
 
end
 
end
  
 
function p.buildimages(params)
 
function p.buildimages(params)
 
local images = {}
 
local images = {}
 +
local upright, link, caption, alt, size  -- size is deprecated
 
if type(params.imageparameters) == 'string' then
 
if type(params.imageparameters) == 'string' then
 
params.imageparameters = {params.imageparameters}
 
params.imageparameters = {params.imageparameters}
Ligne 173 : Ligne 200 :
 
table.insert(images, localdata[k])
 
table.insert(images, localdata[k])
 
end
 
end
if #images == 0 and item then
+
 +
-- Images de Wikidata
 +
if #images == 0 and localdata.item then
 
if params.property then
 
if params.property then
images = wikidata.getClaims{item= item, property = params.property} or {}
+
params.wikidata = {entity = localdata.item, property = params.property}
if #images > 0 then
 
addwikidatacat(params.property)
 
end
 
 
end
 
end
 
if params.wikidata then
 
if params.wikidata then
images = params.wikidata()
+
local wdq = params.wikidata
if type(images) == 'string' then
+
if type(wdq) == 'table' then
return images
+
wdq.entity = wdq.entity or localdata.item
end -- c'est probablement une erreur dans la requête => afficher le message
+
images = wikidata.getClaims(wdq)
 +
end
 +
if type(wdq) == 'function' then
 +
images = params.wikidata()
 +
if type(images) == 'string' then
 +
return images
 +
end --c'est probablement une erreur dans la requête => afficher le message
 +
end
 +
if (not images) then
 +
images = {}
 +
end
 +
if (#images > 0) and (params.wikidata.property) then
 +
addwikidatacat(params.wikidata.property)
 +
end
 +
-- Récupération des légendes de Wikidata (par P2096 seulement, à rendre optionnel et plus flexible)
 +
if type(images[1]) == 'table' then
 +
for i, j in pairs(images) do
 +
if j.mainsnak.snaktype ~= 'value' then
 +
return
 +
end
 +
local wdcaptions, wdcaption
 +
local q = images[i].qualifiers
 +
if q then
 +
wdcaptions = q['P2096']
 +
end
 +
if wdcaptions then
 +
for k, l in pairs(wdcaptions) do
 +
if l.datavalue.value and l.datavalue.value.language == lang then
 +
wdcaption = wd.formatSnak(l)
 +
end
 +
end
 +
end
 +
if wdcaption and caption then -- si deux légendes, désactivées pour éviter les conflits
 +
caption = nil
 +
elseif wdcaption then
 +
caption = wdcaption
 +
end
 +
if i > (params.numval) then
 +
images[i] = nil
 +
else
 +
images[i] = j.mainsnak.datavalue.value
 +
end
 +
end
 +
end
 
end
 
end
 
end
 
end
  
 +
-- Images par défaut
 
if #images == 0 then
 
if #images == 0 then
 
if params.maintenancecat then
 
if params.maintenancecat then
local maintenancecat = getvalue(params.maintenancecat, params)
+
addmaintenancecat(params.maintenancecat, params.sortkey)
addmaintenancecat(maintenancecat, params.sortkey)
 
 
end
 
end
 
if params.defaultimages then
 
if params.defaultimages then
Ligne 197 : Ligne 266 :
 
if type(images) == 'string' then
 
if type(images) == 'string' then
 
images = {images}
 
images = {images}
 +
end
 +
upright = params.defaultimageupright
 +
caption = params.defaultimagecaption
 +
link = params.defaultimagelink
 +
alt = params.defaultimagealt
 +
if not alt and ( images[1] == 'Defaut.svg' or images[1] == 'Defaut 2.svg' ) then
 +
alt = 'une illustration sous licence libre serait bienvenue'
 
end
 
end
 
end
 
end
Ligne 203 : Ligne 279 :
 
return nil
 
return nil
 
end
 
end
-- extrait les images des valeurs Wikidata
+
if type(images[1]) == 'table' then
+
upright = upright or getvalue(params.uprightparameter) or params.defaultupright or "1.2"
for i, j in pairs(images) do
+
link = link or getvalue(params.linkparameter) or params.defaultlink
if j.mainsnak.snaktype ~= 'value' then
+
caption = caption or getvalue(params.captionparameter) or params.defaultcaption
return
+
alt = alt or getvalue( params.altparameter) or params.defaultalt
end
+
 
if i > (params.numval) then
+
-- taille avec "size" (obsolète)
images[i] = nil
+
size = size or getvalue(params.sizeparameter) or params.defaultsize -- deprecated
else
+
if size then
images[i] = j.mainsnak.datavalue.value
+
local numsize = size:gsub('px', '')
end
+
numsize = mw.ustring.gsub(numsize, 'x.*', '')
 +
numsize = tonumber(numsize)
 +
if type(numsize) ~= 'number' or numsize > 280 then
 +
addmaintenancecat("taille d'image invalide")
 +
end
 +
if tonumber(size) then
 +
size = size .. 'px'
 
end
 
end
 +
size = '|' .. size
 +
else
 +
size = ''
 
end
 
end
local captiontext = localdata[params.captionparameter] or params.defaultcaption
+
local size = localdata[params.sizeparameter] or params.defaultsize or '280x400px'
 
local numsize = mw.ustring.gsub(size, 'x.*', '')
 
numsize = numsize:gsub('px', '')
 
numsize = tonumber(numsize)
 
if type(numsize) ~= 'number' or numsize > 280 then
 
addmaintenancecat("taille d'image invalide")
 
end
 
if type(captiontext) == 'function' then
 
captiontext = captiontext(localdata)
 
end
 
 
local style = params.style or {padding ='2px 0',}
 
local style = params.style or {padding ='2px 0',}
  
Ligne 236 : Ligne 311 :
 
return
 
return
 
end
 
end
imagesString = imagesString ..  '[[Fichier:' .. image .. '|frameless|' .. size
+
imagesString = imagesString ..  '[[Fichier:' .. image .. size .. '|frameless'
if #images == 1 then
+
if alt then
imagesString = imagesString .. '|center'
+
imagesString = imagesString .. '|alt=' .. alt
 +
end
 +
if link then
 +
imagesString = imagesString .. '|link=' .. link
 
end
 
end
if image.upright then
+
if upright then
imagesString = imagesString .. '|upright=' .. image.upright
+
imagesString = imagesString .. '|upright=' .. upright
else
+
elseif #images > 1 then
 
imagesString = imagesString .. '|upright=' .. ( 1 / #images )
 
imagesString = imagesString .. '|upright=' .. ( 1 / #images )
 
end
 
end
Ligne 254 : Ligne 332 :
  
 
-- Partie légende
 
-- Partie légende
local caption = mw.html.create('p')
+
local captionobj
if captiontext then
+
if caption then
caption
+
captionobj = mw.html.create('p')
:wikitext(captiontext)
+
:wikitext(caption)
 
:css(params.style or {})
 
:css(params.style or {})
 
:addClass("legend")
 
:addClass("legend")
Ligne 266 : Ligne 344 :
 
local separator
 
local separator
 
if params.separator then
 
if params.separator then
local separatorStyle = params['separator style'] or {}
+
separator = separator(params)
separatorStyle.height = separatorStyle.height or '2px'
 
separatorStyle['background-color'] = separatorStyle['background-color'] or maincolor
 
separator = mw.html.create('hr')
 
separator:css( separatorStyle )
 
 
end
 
end
return mw.html.create('div'):node(image):node(caption):node(separator):done()
+
return mw.html.create('div')
 +
:node(image)
 +
:node(captionobj)
 +
:node(separator)
 +
:done()
 
end
 
end
  
 
function p.buildtext(params)
 
function p.buildtext(params)
 
local class = params.class or ''
 
local class = params.class or ''
local style = defaultstyle['boldline']
+
local style = {
 +
['text-align'] = 'center',
 +
['font-weight'] = 'bold'
 +
}
 
if params.style then
 
if params.style then
 
for i, j in pairs(params.style) do
 
for i, j in pairs(params.style) do
Ligne 303 : Ligne 384 :
 
local style = params.style or {}
 
local style = params.style or {}
 
local value, number =  getvalue(params.value, params)
 
local value, number =  getvalue(params.value, params)
if not value then
+
if (value == valueexpl) then
 +
value = nil
 +
params.wikidata.expl = false
 +
end
 +
if (not value) then
 
value, number =  getWikidataValue(params, 'wikidata')
 
value, number =  getWikidataValue(params, 'wikidata')
 
end
 
end
 
if (not value) and (params.property) then
 
if (not value) and (params.property) then
value, number = expandquery({property = params.property})  -- the property key takes a string value,  that would not work well using the wikidata key
+
value, number = expandquery{ property = params.property, ucfirst = params.ucfirst }
 
end
 
end
 
if not value then
 
if not value then
Ligne 314 : Ligne 399 :
 
if value == '-' then
 
if value == '-' then
 
return nil
 
return nil
 +
end
 +
if not number then
 +
number = 0 -- == indéfini
 
end
 
end
  
Ligne 325 : Ligne 413 :
  
 
local label = params.label
 
local label = params.label
if number == 'plural' and (params.plurallabel) then
+
if number > 1 and (params.plurallabel) then
 
label = params.plurallabel
 
label = params.plurallabel
elseif number == 'singular' and (params.singularlabel) then
+
elseif number == 1 and (params.singularlabel) then
label = singularlabel
+
label = params.singularlabel
 
end
 
end
 
if type(label) == 'function' then
 
if type(label) == 'function' then
label = label(localdata, item)
+
label = label(localdata, localdata.item)
 
end
 
end
  
Ligne 366 : Ligne 454 :
 
end
 
end
  
function p.buildtable(params)
+
function p.buildsuccession(params)
local tab = mw.html.create('table'):css(params.style or {})
+
if not params.value then
local title
+
return nil
if params.title then
+
end
local text
+
if type(params.title) == 'string' then -- raccourci moche mais pratique : n'utiliser qu'une chaîne pour le titre
+
--local style = params.style or {}
text = params.title
+
--style['text-align'] = style['text-align'] or 'center'
params.title = {}
+
--style['color'] = style['color'] or '#000000'
else
+
--style['background-color'] = style['background-color'] or '#F9F9F9'
text = params.title.value or error('no value provided for this title')
+
end
+
local rowI = mw.html.create('tr')
local titlestyle = params.title.style or {['text-align'] = 'center', color = '000000'}
+
if not titlestyle['background-color'] then
+
local colspan = '2'
titlestyle['background-color'= maincolor
+
cellI = mw.html.create('td')
end
+
:attr({colspan = colspan})
local colspan = params.title.colspan or '2'
+
:attr({align = 'center'})
title = mw.html.create('caption')
+
:attr({colspan = 2})
+
local styleT = {}
:css(titlestyle)
+
styleT['background-color'] = 'transparent'
:wikitext(text)
+
styleT['width'] = '100%'
 +
tabC = mw.html.create('table')
 +
:attr({cellspacing = '0'})
 +
:css(styleT)
 +
 +
local row = mw.html.create('tr')
 +
 
 +
local color = params.color
 +
 
 +
local style = {}
 +
local arrowLeft
 +
local arrowRight
 +
 +
if color == 'default' then
 +
style['background-color'] = '#E6E6E6'
 +
arrowLeft = '[[Fichier:Fleche-defaut-gauche.png|13px|alt=Précédent|link=]]'
 +
arrowRight = '[[Fichier:Fleche-defaut-droite.png|13px|alt=Précédent|link=]]'
 +
else
 +
style['background-color'] = color
 +
arrowLeft = '[[Fichier:Fleche-defaut-gauche-gris-32.png|13px|alt=Suivant|link=]]'
 +
arrowRight = '[[Fichier:Fleche-defaut-droite-gris-32.png|13px|alt=Suivant|link=]]'
 +
end
 +
 +
local styleTrans = {}
 +
styleTrans['background-color'] = '#F9F9F9'
 +
 +
local values = params.value
 +
local before = values['before']
 +
local center = values['center']
 +
local after = values['after']
 +
 +
local widthCell = '44%'
 +
if center then
 +
widthCenter = '28%'
 +
widthCell = '29%'
 +
end
 +
 +
local formattedbefore
 +
if before then
 +
formattedbefore = mw.html.create('td')
 +
:attr({valign = 'middle'})
 +
:attr({align = 'left'})
 +
:attr({width = '5%'})
 +
:css(style)
 +
:wikitext(arrowLeft)
 +
:done()
 +
row:node(formattedbefore)
 +
formattedbefore = mw.html.create('td')
 +
:attr({width = '1%'})
 +
:css(style)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedbefore)
 +
formattedbefore = mw.html.create('td')
 +
:attr({align = 'left'})
 +
:attr({valign = 'middle'})
 +
:attr({width = widthCell})
 +
:css(style)
 +
:wikitext(before)
 +
:done()
 +
row:node(formattedbefore)
 +
else
 +
formattedbefore = mw.html.create('td')
 +
:attr({valign = 'middle'})
 +
:attr({align = 'left'})
 +
:attr({width = '5%'})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedbefore)
 +
formattedbefore = mw.html.create('td')
 +
:attr({width = '1%'})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedbefore)
 +
formattedbefore = mw.html.create('td')
 +
:attr({align = 'left'})
 +
:attr({valign = 'middle'})
 +
:attr({width = widthCell})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedbefore)
 +
end
 +
 +
local formattedcenter
 +
formattedcenter = mw.html.create('td')
 +
:attr({width = '1%'})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedcenter)
 +
 +
if center then
 +
formattedcenter = mw.html.create('td')
 +
:attr({align = 'center'})
 +
:attr({valign = 'middle'})
 +
:attr({width = widthCenter})
 +
:css(style)
 +
:wikitext(center)
 +
:done()
 +
row:node(formattedcenter)
 +
formattedcenter = mw.html.create('td')
 +
:attr({width = '1%'})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedcenter)
 +
end
 +
 +
local formattedafter
 +
if after then
 +
formattedafter = mw.html.create('td')
 +
:attr({align = 'right'})
 +
:attr({valign = 'middle'})
 +
:attr({width = widthCell})
 +
:css(style)
 +
:wikitext(after)
 +
:done()
 +
row:node(formattedafter)
 +
formattedbefore = mw.html.create('td')
 +
:attr({width = '1%'})
 +
:css(style)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedbefore)
 +
formattedafter = mw.html.create('td')
 +
:attr({align = 'right'})
 +
:attr({valign = 'middle'})
 +
:attr({width = '5%'})
 +
:css(style)
 +
:wikitext(arrowRight)
 +
:done()
 +
row:node(formattedafter)
 +
else
 +
formattedafter = mw.html.create('td')
 +
:attr({align = 'right'})
 +
:attr({valign = 'middle'})
 +
:attr({width = widthCell})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedafter)
 +
formattedbefore = mw.html.create('td')
 +
:attr({width = '1%'})
 +
:css(styleTrans)
 +
:wikitext('')
 +
:done()
 +
row:node(formattedbefore)
 +
formattedafter = mw.html.create('td')
 +
:attr({align = 'right'})
 +
:attr({valign = 'middle'})
 +
:attr({width = '5%'})
 +
:css(styleTrans)
 +
:wikitext('')
 
:done()
 
:done()
 +
row:node(formattedafter)
 +
end
 +
 +
row:done()
 +
tabC:node(row)
 +
tabC:done()
 +
cellI:node(tabC)
 +
cellI:done()
 +
rowI:node(cellI)
 +
rowI:allDone()
 +
 +
return rowI
 +
end
 +
 +
function p.buildrow1col(params)
 +
 +
if not params.value then
 +
return nil
 +
end
 +
 +
--local style = params.style or {}
 +
--style['text-align'] = style['text-align'] or 'center'
 +
--style['color'] = style['color'] or '#000000'
 +
--style['background-color'] = style['background-color'] or '#F9F9F9'
 +
local class = params.class
 +
local rowcolor
 +
if params.color == 'secondcolor' then
 +
rowcolor = secondcolor
 +
else
 +
rowcolor = params.color
 
end
 
end
local rows = {} -- does not add the rows directly to tab: check if some rows are non empty beoforehand so that we do not add a title if there are no data to show
 
 
 
for k, l in pairs(params.rows) do
+
local style = {}
 +
style['padding'] = '4px'
 +
style['text-align'] = 'center'
 +
style['background-color'] = rowcolor or '#F9F9F9'
 +
style['color'] = '#000000'
 +
 +
local text = params.value
 +
 
 +
local colspan ='2'
 +
 
 +
local formattedlabel
 +
formattedlabel = mw.html.create('th')
 +
:attr({colspan = colspan})
 +
:css(style)
 +
:wikitext(text)
 +
:done()
 +
 
 +
local row = mw.html.create('tr')
 +
:addClass(class)
 +
:css(style)
 +
:node(formattedlabel)
 +
:done()
 +
 +
return row
 +
end
 +
 
 +
function p.buildtable(params)
 +
local tab = mw.html.create('table'):css(params.style or {})
 +
 
 +
-- CREATE ROWS
 +
local rows = {}
 +
for k, l in pairs(params.rows) do
 
if type(l) == 'table' and l.type == 'multi' then -- when a single function is used for return several rows
 
if type(l) == 'table' and l.type == 'multi' then -- when a single function is used for return several rows
 
table.remove(params.rows, k)
 
table.remove(params.rows, k)
Ligne 402 : Ligne 705 :
  
 
if type(l) == 'function' then --accepte les fonctions qui retournent des tables
 
if type(l) == 'function' then --accepte les fonctions qui retournent des tables
l = l(localdata, item)
+
l = l(localdata, localdata.item)
 
end
 
end
 
if type(l) == 'nil' then
 
if type(l) == 'nil' then
Ligne 413 : Ligne 716 :
 
end
 
end
 
end
 
end
if #rows > 0 then
+
if #rows == 0 then
if title then
+
return nil
tab:node(title)
+
end
 +
 
 +
-- ADD TITLE
 +
local title
 +
if params.title or params.singulartitle or params.pluraltitle then
 +
local text
 +
if #rows > 1 and params.pluraltitle then
 +
text = params.pluraltitle
 +
elseif #rows == 1 and params.singulartitle then
 +
text = params.singulartitle
 +
else
 +
text = params.title
 
end
 
end
for i, j in pairs (rows) do
+
 
tab:node(j)
+
local style = params.titlestyle or {}
end
+
style['text-align'] = style['text-align'] or 'center'
tab:allDone()
+
style['color'] = style['color'] or thirdcolor
return tab
+
style['background-color'] = style['background-color'] or maincolor
else
+
 
return nil
+
local colspan ='2'
 +
title = mw.html.create('caption')
 +
:attr({colspan = colspan})
 +
:css(style)
 +
:wikitext(text)
 +
:done()
 +
end
 +
 +
if title then
 +
tab:node(title)
 +
end
 +
 +
for i, j in pairs (rows) do
 +
tab:node(j)
 +
end
 +
 +
if params.separator then
 +
local separator = p.separator(params)
 +
tab:node(separator)
 
end
 
end
 +
tab:allDone()
 +
return tab
 
end
 
end
  
Ligne 438 : Ligne 772 :
 
end
 
end
  
function p.buildmap(params)
+
function p.buildmap(params)-- TODO  : gestion de plusieurs points
 +
 
 +
-- paramètre d'affichage
 
local maplist = getvalue(params.maps)
 
local maplist = getvalue(params.maps)
local pointimage = params.pointimage
+
local pointtype = params.pointtype
 
local maptype = params.maptype -- choisit le type de carte le plus approprié (relief, administratif, etc.)
 
local maptype = params.maptype -- choisit le type de carte le plus approprié (relief, administratif, etc.)
 
if type(maplist) == 'function' then
 
if type(maplist) == 'function' then
maplist = maplist(localdata, item)
+
maplist = maplist(localdata, localdata.item)
 
end
 
end
 
local width = tonumber(params.width) or 280
 
local width = tonumber(params.width) or 280
Ligne 450 : Ligne 786 :
 
return 'image trop grande, la largeur doit être inférieure ou égale à 280px'
 
return 'image trop grande, la largeur doit être inférieure ou égale à 280px'
 
end
 
end
local latitude, longitude
+
 
 +
-- récupération des données locales
 +
local latitude, longitude, globe = params.latitude, params.longitude, params.globe
 
if type(params.latitude) == 'function' then
 
if type(params.latitude) == 'function' then
latitude, longitude = params.latitude(localdata, item), params.longitude(localdata, item)
+
latitude, longitude = params.latitude(localdata, localdata.item), params.longitude(localdata, localdata.item)
 
else
 
else
 
latitude, longitude = localdata[params.latitude], localdata[params.longitude]
 
latitude, longitude = localdata[params.latitude], localdata[params.longitude]
 
end
 
end
if (not latitude or not longitude) and item and params.wikidata then
+
if not type(params.wikidata) == 'function' then
+
-- récupération des données wikidata
return error('valeur wikidata incorrecte pour la géolocalisation')
+
if (not latitude or not longitude) and params.wikidata then
 +
local query = params.wikidata
 +
if type(query) == 'function' then
 +
query = query()
 
end
 
end
local val = params.wikidata(item, query)
+
if not query then
if not val then
 
 
return nil
 
return nil
 
end
 
end
if (not type(val) == 'table')  then
+
query.excludespecial = true
return error("mauvaise requête pour les coordonnées de géolocalisation")
+
query.entity = query.entity or localdata.item
end
+
local claims = wikidata.getClaims(query)
val = val[1]
+
if not claims then
if val.mainsnak.snaktype == 'value' then
+
return nil
latitude, longitude = val.mainsnak.datavalue.value.latitude, val.mainsnak.datavalue.value.longitude
 
 
end
 
end
 +
local val = wd.formatSnak( claims[1].mainsnak )
 +
latitude, longitude, globe = val.latitude, val.longitude, val.globe
 
end
 
end
 +
 
if not latitude or not longitude then
 
if not latitude or not longitude then
 
return nil
 
return nil
 
end
 
end
local newparams = {maplist = maplist, pointimage = pointimage, width = width, item = item, latitude = latitude, longitude = longitude}
+
local newparams = {maplist = maplist, pointtype = pointtype, maptype = maptype, width = width, item = localdata.item, latitude = latitude, longitude = longitude, globe = globe, marker=params.marker, default_zoom=params.default_zoom}
 
if params.params and type(params.params) == 'table' then -- paramètres additionnels
 
if params.params and type(params.params) == 'table' then -- paramètres additionnels
 
for i, j in pairs(params.params) do
 
for i, j in pairs(params.params) do
Ligne 482 : Ligne 824 :
 
end
 
end
 
return mapmod.multimap(newparams)
 
return mapmod.multimap(newparams)
 +
end
 +
 +
function p.buildexternaltext(params)
 +
local value = getvalue(params.value)
 +
if value and (type(value) == 'string') then
 +
externaltext = externaltext .. value
 +
end
 
end
 
end
  
Ligne 489 : Ligne 838 :
 
end
 
end
 
 
local class = 'navbar noprint ' .. (params.class or '')
+
local class = 'navbar noprint bordered ' .. (params.class or '')
 
local style = params.style or {}
 
local style = params.style or {}
 
style['border-top'] = style['border-top'] or '1px solid ' .. maincolor
 
style['border-top'] = style['border-top'] or '1px solid ' .. maincolor
 
 
local backlinkstr = '[' .. tostring( mw.uri.fullUrl( page.name, '&veaction=edit&section=0' ) ) .. ' ' .. i18n['edit'] .. ']'
+
local backlinkstr = '[' .. tostring( mw.uri.fullUrl( page.name, 'veaction=edit&section=0' ) ) .. ' ' .. i18n['edit'] .. ']'
.. ' - [' .. tostring( mw.uri.fullUrl( page.name, '&action=edit&section=0' ) ) .. ' ' .. i18n['edit code'] .. ']'
+
.. ' - [' .. tostring( mw.uri.fullUrl( page.name, 'action=edit&section=0' ) ) .. ' ' .. i18n['edit code'] .. ']'
  
 
local itemlinkstr
 
local itemlinkstr
if item then
+
if localdata.item then
itemlinkstr = '[[d:' .. item.id .. '|' .. i18n['edit item'] .. ']]'
+
itemlinkstr = '[[d:' .. localdata.item.id .. '|' .. i18n['edit item'] .. ']]'
 
end
 
end
 
local editstr = backlinkstr
 
local editstr = backlinkstr
Ligne 509 : Ligne 858 :
 
:wikitext(editstr)
 
:wikitext(editstr)
 
:done()
 
:done()
local doclinkstr = '[[Image:Gtk-dialog-info.svg|12px|link=' .. localdata.templatename .. '|' .. i18n['see doc'] .. ']]'
+
local doclinkstr = '[[Image:Info Simple.svg|12px|link=' .. localdata.templatename .. '|' .. i18n['see doc'] .. ']]'
 
-- si ce lien ne marche pas toujours, il faut ajouter un variable pour le nom de l'infobox récupéré par le frame
 
-- si ce lien ne marche pas toujours, il faut ajouter un variable pour le nom de l'infobox récupéré par le frame
 
local doclinkspan = mw.html.create('span')
 
local doclinkspan = mw.html.create('span')
Ligne 526 : Ligne 875 :
 
function p.buildblock(block)
 
function p.buildblock(block)
 
if type(block) == 'function' then
 
if type(block) == 'function' then
block = block()
+
block = block( localdata )
 
end
 
end
  
Ligne 539 : Ligne 888 :
 
['table'] = p.buildtable,
 
['table'] = p.buildtable,
 
['row'] = p.buildrow,
 
['row'] = p.buildrow,
 +
['row1col'] = p.buildrow1col,
 +
['succession'] = p.buildnavbox,
 
['text'] = p.buildtext,
 
['text'] = p.buildtext,
 
['title'] = p.buildtitle,
 
['title'] = p.buildtitle,
Ligne 548 : Ligne 899 :
 
end
 
end
  
function p._build(modulename, params, templatename)
+
function p.build()
 +
 +
localdata = require( 'Module:Infobox/Localdata' )
 +
item = localdata.item
  
-- fill-up global variable localdata using params
+
-- assign rank to the infobox, "secondary" means special formatting like no displaytitle for coordinates
for i, j in pairs(params) do
 
if j and mw.text.trim(j) ~= '' then -- empty parameters are ignored
 
localdata[i] = j
 
end
 
end
 
localdata.templatename = templatename or modulename
 
-- guess "rank" of the infobox
 
 
local infoboxrank = 'main' -- main infobox of the page, with coordinates displayed in title etc.
 
local infoboxrank = 'main' -- main infobox of the page, with coordinates displayed in title etc.
 
if page.namespace ~= 0 then
 
if page.namespace ~= 0 then
 
infoboxrank = 'secondary'
 
infoboxrank = 'secondary'
 +
end
 +
-- if infobox is linked to another item: rank = secondary
 +
if localdata.item then
 +
local itemlink = mw.wikibase.sitelink(localdata.item.id)
 +
local pagetitle = mw.title.getCurrentTitle().text
 +
if (itemlink or '') ~= pagetitle then
 +
infoboxrank = 'secondary'
 +
end
 
end
 
end
 
localdata.infoboxrank = infoboxrank
 
localdata.infoboxrank = infoboxrank
  
-- load wikidata item as a global variable:
 
if localdata.wikidata == 'non' then
 
item = nil
 
elseif (not localdata.wikidata) or (localdata.wikidata == '') then
 
item = mw.wikibase.getEntityObject()
 
else
 
item = nil -- topic of the infobox corresponds to another Wikidata item, should eventually be fetched through arbitrary access
 
localdata.infoboxrank = 'secondary'
 
end
 
 
 
-- load infobox module page
 
-- load infobox module page
moduledata = require('Module:Infobox/' .. modulename)
+
local moduledata = require('Module:Infobox/' .. localdata.modulename)
moduledata.name = modulename
+
moduledata.name = localdata.modulename
 
-- defines main color
 
-- defines main color
 
maincolor = localdata['couleur infobox'] or localdata['couleur boîte'] or moduledata.maincolor or maincolor
 
maincolor = localdata['couleur infobox'] or localdata['couleur boîte'] or moduledata.maincolor or maincolor
 +
secondcolor =  moduledata.secondcolor or secondcolor
 +
thirdcolor =  moduledata.thirdcolor or thirdcolor
 
if maincolor:match( '^%x%x%x%x%x%x$' ) or maincolor:match( '^%x%x%x$' ) then
 
if maincolor:match( '^%x%x%x%x%x%x$' ) or maincolor:match( '^%x%x%x$' ) then
 
maincolor = '#' .. maincolor
 
maincolor = '#' .. maincolor
Ligne 591 : Ligne 938 :
 
-- style
 
-- style
 
local style = moduledata.style or {}
 
local style = moduledata.style or {}
if not style['max-wdith'] then
+
if not style['max-width'] then
 
style['max-width'] = '300px'
 
style['max-width'] = '300px'
 
end
 
end
Ligne 603 : Ligne 950 :
 
infobox :node(p.buildfooter(moduledata.footer))
 
infobox :node(p.buildfooter(moduledata.footer))
 
:done()
 
:done()
+
 
 
return tostring(infobox) .. externaltext, maintenance
 
return tostring(infobox) .. externaltext, maintenance
end
 
 
function p.build(frame)
 
local name =  frame.args.nom
 
local parent = frame:getParent()
 
local templatename = parent:getTitle() -- au cas où il soit différent du nom du module
 
local params = parent.args
 
return p._build(name, params, templatename)
 
 
end
 
end
  
 
return p
 
return p

Version actuelle datée du 20 mai 2017 à 09:18

La documentation pour ce module peut être créée à Module:Infobox/doc

local p = {}
local lang = 'fr'

local item = nil -- l'élément Wikidata lié
local localdata = {}-- données concernant les paramètres passés au modèle
local page = { -- données concernant la page où est affichée l'infobox
	name = mw.title.getCurrentTitle().prefixedText,
	namespace =  mw.title.getCurrentTitle().namespace
}
local maincolor, secondcolor, thirdcolor = '#E1E1E1', '#E1E1E1', '#000000'
-- l'objet principal à retournerp
local infobox = mw.html.create('div')

-- objes secondaires à retourner
local maintenance = '' -- chaîne retournfoée avec le module : cats de maintenance
local externaltext = '' -- par exemple coordonnées en titre
-- modules importés
local wikidata = require('Module:Interface Wikidata').fromLua
local valueexpl = wikidata.translate("activate-query")
local linguistic = require "Module:Linguistique"
local wd = require 'Module:Wikidata'
local mapmod = require "Module:Carte"

local i18n = {
	['see doc'] = 'Documentation du modèle',
	['edit'] = 'modifier',
	['edit code'] = 'modifier le code',
	['edit item'] = 'modifier Wikidata',
	['tracking cat'] = "Page utilisant des données de Wikidata",
	['invalid block type'] = "Bloc de données invalide dans le module d'infobox",
	['default cat'] = "Maintenance des infobox",
}

local function addwikidatacat(prop)
	maintenance = maintenance .. wikidata.addtrackingcat(prop)
end

local function expandquery(query)
	local value, number -- valeur à retourner, nombre de valeurs pour accorder le libellé
	if not query.entity then
		query.entity = localdata.item
	end
	if not query.conjtype then
		query.conjtype = 'comma'
	end
	local claims = wikidata.getClaims(query)
		if (not claims) then
		return nil
	end
	return wikidata.formatAndCat(query), #claims -- pour l'accord au pluriel
end

local function getWikidataValue(params, wikidataparam)
	-- Récupère la valeur Wikidata pour la valeur, soit dans le paramètre "wikidata" soit dans le praramètre "property"
	if not localdata.item then
		return nil
	end
	local v, valnum -- la valeur à retourner, et le nombre de de valeurs (pour l'accord grammatical)
	
	if not wikidataparam then -- par défaut la valeur wikidata est dans le paramètre "wikidata" mais dans les structures composées comme "title", il y a plusieurs paramètres wikidata
		wikidataparam = 'wikidata'
	end

	if params[wikidataparam] then
		if type(params[wikidataparam]) == 'function' then
			v, valnum = params[wikidataparam](localdata.item)
		elseif type(params[wikidataparam]) == 'table' then
			v, valnum = expandquery(params[wikidataparam])
		else
			v, valnum = params[wikidataparam]
		end
	end
	if not v then
		return nil
	end
	v = linguistic.ucfirst(v)
	return v, valnum
end

local function getvalue(val, params)
	if type(val) == 'string' then
		return localdata[val]
	elseif type(val) == 'function' then
		return val(localdata, localdata.item, params)
	elseif type(val) == 'table' then
		for i, j in pairs(val) do -- si plusieurs paramètres possibles (legacy de vieux code), prendre le preimeir non bide
			if localdata[j] then
				return localdata[j]
			end
		end
	end
end

local function addmaintenancecat(cat, sortkey)
	if page.namespace ~= 0 then
		return ''
	end
	if cat then
		maintenance = maintenance .. '[[Category:' .. cat .. '|' .. (sortkey or page.name) .. ']]'
	end
end

function p.separator(params)
	local style = params['separator style'] or {}
	style.height = style.height or '2px'
	style['background-color'] = style['background-color'] or maincolor
	
	return mw.html.create('hr'):css( style )	
end

function p.buildtitle(params)
	local text = getvalue(params.value, params) or params.textdefaultvalue or  getWikidataValue(params) or mw.title.getCurrentTitle().text
	local subtext = getvalue(params.subtitle) or  getWikidataValue(params, 'wikidatasubtitle') or params.subtitledefaultvalue
	if subtext and (subtext ~= text) then
		text = text .. '<br /><small>' .. subtext .. '</small>'
	end
	local icon = params.icon or ''
	if icon ~= '' and not params.large then
		icon = 'icon ' .. icon
	end
	local class = 'entete ' .. icon
	
	-- overwrites with those provided in the module
	local style = {}
	style['background-color'] = maincolor
	style['color'] = thirdcolor
	if params.style then
		for i, j in pairs(params.style) do
			style[i] = j
		end
	end
	local title = mw.html.create('div')
		:addClass(class)
		:css(style)
		:tag('div')
			:wikitext(text)
		:allDone()
	return title
end

function p.buildnavbox(params)
	
	-- définition du style
	local class = "overflow nav " .. (params.class or '')
	local style = params.style or {}

	if params.separated then -- options pour ajouter une ligne de séparation au dessus
		class = class .. ' bordered'
		style['border-top'] = '1px solid' .. maincolor
	end

	-- ajustement des paramètres de données
	params.previousval = params.previousval or params.previousparameter -- nom de paramètre obsolète
	params.nextval = params.nextval or params.nextparameter
	
	if params.previousproperty then
		params.previouswikidata = {property = params.previousproperty}
	end
	if params.nextproperty then
		params.nextwikidata = {property = params.nextproperty}
	end
	

	local previousval = getvalue(params.previousval, params) or getWikidataValue(params, 'previouswikidata')
	local nextval = getvalue(params.nextval, params) or getWikidataValue(params, 'nextwikidata')
	
	local navbox
	if params.inner then -- pour celles qui sont à l'intérieur d'une table
		navbox = mw.html.create('tr'):tag('th'):attr('colspan', 2)
		style['font-weight'] = style['font-weight'] or 'normal'
	else
		navbox = mw.html.create('div')
	end
	
	navbox
		:addClass(class)
		:css(style)
		:tag('div')
			:addClass('prev_bloc')
			:wikitext(previousval)
			:done()
		:tag('div')
			:addClass('next_bloc')
			:wikitext(nextval)
			:done()
		:allDone()
	return navbox
end

function p.buildimages(params)
	local images = {}
	local upright, link, caption, alt, size  -- size is deprecated
	if type(params.imageparameters) == 'string' then
		params.imageparameters = {params.imageparameters}
	end
	if not params.imageparameters then -- s'il n'y a pa de paramètre image, continuer, peut-être y-a-t-il une image par défaut définie dans le module d'infobox
		params.imageparameters = {}
	end
	for j, k in ipairs(params.imageparameters) do
		table.insert(images, localdata[k])
	end
	
	-- Images de Wikidata 
	if #images == 0 and localdata.item then
		if params.property then
			params.wikidata = {entity = localdata.item, property = params.property}
		end
		if params.wikidata then
			local wdq = params.wikidata
			if type(wdq) == 'table' then
				wdq.entity = wdq.entity or localdata.item
				images = wikidata.getClaims(wdq)
			end
			if type(wdq) == 'function' then
				images = params.wikidata()
				if type(images) == 'string' then
					return images
				end --c'est probablement une erreur dans la requête => afficher le message
			end
			if (not images) then
				images = {}
			end
			if (#images > 0) and (params.wikidata.property) then
				addwikidatacat(params.wikidata.property)
			end
			-- Récupération des légendes de Wikidata (par P2096 seulement, à rendre optionnel et plus flexible)
			if type(images[1]) == 'table' then
				for i, j in pairs(images) do
					if j.mainsnak.snaktype ~= 'value' then
						return
					end
					local wdcaptions, wdcaption
					local q = images[i].qualifiers
					if q then
						wdcaptions = q['P2096']
					end
					if wdcaptions then
						for k, l in pairs(wdcaptions) do
							if l.datavalue.value and l.datavalue.value.language == lang then
								wdcaption = wd.formatSnak(l)
							end
						end
					end
					if wdcaption and caption then -- si deux légendes, désactivées pour éviter les conflits
						caption = nil
					elseif wdcaption then
						caption = wdcaption
					end
					if i > (params.numval) then
						images[i] = nil
					else
						images[i] = j.mainsnak.datavalue.value
					end
				end
			end
		end
	end

	-- Images par défaut
	if #images == 0 then
		if params.maintenancecat then
			addmaintenancecat(params.maintenancecat, params.sortkey)
		end
		if params.defaultimages then
			images = params.defaultimages
			if type(images) == 'string' then
				images = {images}
			end
			upright = params.defaultimageupright
			caption = params.defaultimagecaption
			link = params.defaultimagelink
			alt = params.defaultimagealt
			if not alt and ( images[1] == 'Defaut.svg' or images[1] == 'Defaut 2.svg' ) then
				alt = 'une illustration sous licence libre serait bienvenue'
			end
		end
	end
	if #images == 0 then
		return nil
	end
	
	upright = upright or getvalue(params.uprightparameter) or params.defaultupright or "1.2"
	link = link or getvalue(params.linkparameter) or params.defaultlink
	caption = caption or getvalue(params.captionparameter) or params.defaultcaption
	alt = alt or getvalue( params.altparameter) or params.defaultalt

	-- taille avec "size" (obsolète)
	size = size or getvalue(params.sizeparameter) or params.defaultsize -- deprecated
	if size then
		local numsize = size:gsub('px', '')
		numsize = mw.ustring.gsub(numsize, 'x.*', '')
		numsize = tonumber(numsize)
		if type(numsize) ~= 'number' or numsize > 280 then
			addmaintenancecat("taille d'image invalide")
		end
		if tonumber(size) then
			size = size .. 'px'
		end
		size = '|' .. size
	else
		size = ''
	end
	
	local style = params.style or {padding ='2px 0',}

	-- Partie image

	local imagesString = ''
	for i,image in pairs(images) do
		if image == '-' then
			return
		end
		imagesString = imagesString ..  '[[Fichier:' .. image .. size .. '|frameless'
		if alt then
			imagesString = imagesString .. '|alt=' .. alt
		end
		if link then
			imagesString = imagesString .. '|link=' .. link
		end
		if upright then
			imagesString = imagesString .. '|upright=' .. upright
		elseif #images > 1 then
			imagesString = imagesString .. '|upright=' .. ( 1 / #images )
		end
		imagesString = imagesString .. ']]'
	end

	local image = mw.html.create('div')
		:addClass("images")
		:css(style)
		:wikitext(imagesString)

	-- Partie légende
	local captionobj
	if caption then
		captionobj = mw.html.create('p')
			:wikitext(caption)
			:css(params.style or {})
			:addClass("legend")
			:done()
	end
	
	-- séparateur
	local separator
	if params.separator then
		separator = separator(params)
	end
	return mw.html.create('div')
		:node(image)
		:node(captionobj)
		:node(separator)
		:done()
end

function p.buildtext(params)
	local class = params.class or ''
	local style = {
		['text-align'] = 'center',
		['font-weight'] = 'bold'
	}
	if params.style then
		for i, j in pairs(params.style) do
			style[i] = j
		end
	end
	local text = getvalue(params.value, params) or getWikidataValue(params) or params.defaultvalue
	if text == '-' then
		return
	end
	if not text then
		addmaintenancecat(params.maintenancecat, params.sortkey)
		return nil
	end
	local formattedtext = mw.html.create('p')
		:addClass(class)
		:css(style)
		:wikitext(text)
		:done()
	return formattedtext
end

function p.buildrow(params)
	local class = params.class or ''
	local style = params.style or {}
	local value, number =  getvalue(params.value, params)
	if (value == valueexpl) then
		value = nil
		params.wikidata.expl = false
	end
	if (not value) then
		value, number =  getWikidataValue(params, 'wikidata')
	end
	if (not value) and (params.property) then
		value, number = expandquery{ property = params.property, ucfirst = params.ucfirst }
	end
	if not value then
		value = params.defaultvalue
	end
	if value == '-' then
		return nil
	end
	if not number then
		number = 0 -- == indéfini
	end

	if not value then
		if params.maintenancecat then
			local maintenancecat = getvalue(params.maintenancecat, params)
			addmaintenancecat(maintenancecat, params.sortkey)
		end
		return nil
	end

	local label = params.label
	if number > 1 and (params.plurallabel) then
		label = params.plurallabel
	elseif number == 1 and (params.singularlabel) then
		label = params.singularlabel
	end
	if type(label) == 'function' then
			label = label(localdata, localdata.item)
	end

	-- format
	local formattedvalue = mw.html.create('div')
		:wikitext('\n' .. value) -- Le '\n' est requis lorsque value est une liste commençant par '*' ou '#'
		
	if (params.hidden == true)then
		formattedvalue
			:attr({class="NavContent", style="display: none; text-align: left;"})
		formattedvalue = mw.html.create('div')
			:attr({class="NavFrame", title="[Afficher]/[Masquer]", style="border: none; padding: 0;"})
			:node(formattedvalue)
	end
	formattedvalue =  mw.html.create('td')
			:node(formattedvalue)
			:allDone()
	
	local formattedlabel
	if label then
		formattedlabel = mw.html.create('th')
			:attr('scope', 'row')
			:wikitext(label)
			:done()
	end
	local row = mw.html.create('tr')
		:addClass(class)
		:css(style)
		:node(formattedlabel)
		:node(formattedvalue)
		:done()
	
	return row
end

function p.buildsuccession(params)
if not params.value then
		return nil
	end
		
	--local style = params.style or {}
	--style['text-align'] = style['text-align'] or 'center'
	--style['color'] = style['color'] or '#000000'
	--style['background-color'] = style['background-color'] or '#F9F9F9'
	
	local rowI = mw.html.create('tr')
	
	local colspan = '2'
	cellI = mw.html.create('td')
			:attr({colspan = colspan})
			:attr({align = 'center'})
	
	local styleT = {}
	styleT['background-color'] = 'transparent'
	styleT['width'] = '100%'
	tabC = mw.html.create('table')
			:attr({cellspacing = '0'})
			:css(styleT)
	
	local row = mw.html.create('tr')

	local color = params.color

	local style = {}
	local arrowLeft
	local arrowRight
	
	if color == 'default' then
		style['background-color'] = '#E6E6E6'
		arrowLeft = '[[Fichier:Fleche-defaut-gauche.png|13px|alt=Précédent|link=]]'
		arrowRight = '[[Fichier:Fleche-defaut-droite.png|13px|alt=Précédent|link=]]'
	else
		style['background-color'] = color
		arrowLeft = '[[Fichier:Fleche-defaut-gauche-gris-32.png|13px|alt=Suivant|link=]]'
		arrowRight = '[[Fichier:Fleche-defaut-droite-gris-32.png|13px|alt=Suivant|link=]]'
	end
	
	local styleTrans = {}
	styleTrans['background-color'] = '#F9F9F9'
	
	local values = params.value
	local before = values['before']
	local center = values['center']
	local after = values['after']
	
	local widthCell = '44%'
	if center then
		widthCenter = '28%'
		widthCell = '29%'
	end
	
	local formattedbefore
	if before then
		formattedbefore = mw.html.create('td')
			:attr({valign = 'middle'})
			:attr({align = 'left'})
			:attr({width = '5%'})
			:css(style)
			:wikitext(arrowLeft)
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(style)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({align = 'left'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(style)
			:wikitext(before)
			:done()
		row:node(formattedbefore)
	else
		formattedbefore = mw.html.create('td')
			:attr({valign = 'middle'})
			:attr({align = 'left'})
			:attr({width = '5%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedbefore = mw.html.create('td')
			:attr({align = 'left'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
	end
	
	local formattedcenter
	formattedcenter = mw.html.create('td')
		:attr({width = '1%'})
		:css(styleTrans)
		:wikitext('')
		:done()
	row:node(formattedcenter)
	
	if center then
		formattedcenter = mw.html.create('td')
			:attr({align = 'center'})
			:attr({valign = 'middle'})
			:attr({width = widthCenter})
			:css(style)
			:wikitext(center)
			:done()
		row:node(formattedcenter)
		formattedcenter = mw.html.create('td')
			:attr({width = '1%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedcenter)
	end
	
	local formattedafter
	if after then
		formattedafter = mw.html.create('td')
			:attr({align = 'right'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(style)
			:wikitext(after)
			:done()
		row:node(formattedafter)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(style)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedafter = mw.html.create('td')
			:attr({align = 'right'})
			:attr({valign = 'middle'})
			:attr({width = '5%'})
			:css(style)
			:wikitext(arrowRight)
			:done()
		row:node(formattedafter)
	else
		formattedafter = mw.html.create('td')
			:attr({align = 'right'})
			:attr({valign = 'middle'})
			:attr({width = widthCell})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedafter)
		formattedbefore = mw.html.create('td')
			:attr({width = '1%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedbefore)
		formattedafter = mw.html.create('td')
			:attr({align = 'right'})
			:attr({valign = 'middle'})
			:attr({width = '5%'})
			:css(styleTrans)
			:wikitext('')
			:done()
		row:node(formattedafter)
	end
	
	row:done()
	tabC:node(row)
	tabC:done()
	cellI:node(tabC)
	cellI:done()
	rowI:node(cellI)
	rowI:allDone()
	
	return rowI
end

function p.buildrow1col(params)
	
	if not params.value then
		return nil
	end
		
	--local style = params.style or {}
	--style['text-align'] = style['text-align'] or 'center'
	--style['color'] = style['color'] or '#000000'
	--style['background-color'] = style['background-color'] or '#F9F9F9'
	local class = params.class
	local rowcolor
	if params.color == 'secondcolor' then
		rowcolor = secondcolor
	else
		rowcolor = params.color
	end
	
	local style = {}
	style['padding'] = '4px'
	style['text-align'] = 'center'
	style['background-color'] = rowcolor or '#F9F9F9'
	style['color'] = '#000000'
	
	local text = params.value

	local colspan ='2'

	local formattedlabel
	formattedlabel = mw.html.create('th')
		:attr({colspan = colspan})
		:css(style)
		:wikitext(text)
		:done()

	local row = mw.html.create('tr')
		:addClass(class)
		:css(style)
		:node(formattedlabel)
		:done()
	
	return row
end

function p.buildtable(params)
	local tab = mw.html.create('table'):css(params.style or {})

	-- CREATE ROWS
	local rows = {}
		for k, l in pairs(params.rows) do
		if type(l) == 'table' and l.type == 'multi' then -- when a single function is used for return several rows
			table.remove(params.rows, k)
			local count = 0
			for m, n in pairs(l.rows) do
				table.insert(params.rows, k + count, n)
				count = count + 1
			end
			l = params.rows[k]
		end

		if type(l) == 'function' then --accepte les fonctions qui retournent des tables
			l = l(localdata, localdata.item)
		end
		if type(l) == 'nil' then
			--ne rien faire (quand la valeur est originellemenet une fonctin elle peut retourner nil)
		elseif type(l) ~= 'table' then
			return error('les lignes d\'infobox ("rows") doivent être des tables, est ' .. type(l))
		else
			local row = p.buildblock(l)
			table.insert(rows, row)
		end
	end
	if #rows == 0 then
		return nil
	end

	-- ADD TITLE
	local title
	if params.title or params.singulartitle or params.pluraltitle then
		local text
		if #rows > 1 and params.pluraltitle then
			text = params.pluraltitle
		elseif #rows == 1 and params.singulartitle then
			text = params.singulartitle
		else
			text = params.title
		end

		local style = params.titlestyle or {}
		style['text-align'] = style['text-align'] or 'center'
		style['color'] = style['color'] or thirdcolor
		style['background-color'] = style['background-color'] or maincolor

		local colspan ='2'
		title = mw.html.create('caption')
			:attr({colspan = colspan})
			:css(style)
			:wikitext(text)
			:done()
	end
	
	if title then
		tab:node(title)
	end
	
	for i, j in pairs (rows) do
		tab:node(j)
	end
	
	if params.separator then
		local separator = p.separator(params)
		tab:node(separator)
	end
	tab:allDone()
	return tab
end

function p.buildinvalidblock(args)
	addmaintenancecat(defaultcat)
	local text = ''
	if type(args) ~= 'table' then
		text = "Les blocs d'infobox doivent être des tables"
	else
		text = i18n["invalid block type"] .. ' : ' .. (args.type or '??')
	end
	return text
end

function p.buildmap(params)-- TODO  : gestion de plusieurs points

	-- paramètre d'affichage 
	local maplist = getvalue(params.maps)
	local pointtype = params.pointtype
	local maptype = params.maptype -- choisit le type de carte le plus approprié (relief, administratif, etc.)	
	if type(maplist) == 'function' then
		maplist = maplist(localdata, localdata.item)
	end
	local width = tonumber(params.width) or 280
	if width > 280 then
		addmaintenancecat("Erreur d'Infobox/Image trop grande")
		return 'image trop grande, la largeur doit être inférieure ou égale à 280px'
	end

	-- récupération des données locales
	local latitude, longitude, globe = params.latitude, params.longitude, params.globe
	if type(params.latitude) == 'function' then
		latitude, longitude = params.latitude(localdata, localdata.item), params.longitude(localdata, localdata.item)
	else
		latitude, longitude = localdata[params.latitude], localdata[params.longitude]
	end
	
	-- récupération des données wikidata
	if (not latitude or not longitude) and params.wikidata then
		local query = params.wikidata
		if type(query) == 'function' then
			query = query()
		end
		if not query then
			return nil
		end
		query.excludespecial = true
		query.entity = query.entity or localdata.item
		local claims = wikidata.getClaims(query)
		if not claims then
			return nil
		end
		local val = wd.formatSnak( claims[1].mainsnak )
		latitude, longitude, globe = val.latitude, val.longitude, val.globe
	end
	
	if not latitude or not longitude then
		return nil
	end
	local newparams = {maplist = maplist, pointtype = pointtype, maptype = maptype, width = width, item = localdata.item, latitude = latitude, longitude = longitude, globe = globe, marker=params.marker, default_zoom=params.default_zoom}
	if params.params and type(params.params) == 'table' then -- paramètres additionnels
		for i, j in pairs(params.params) do
			newparams[i] = j
		end
	end
	return mapmod.multimap(newparams)
end

function p.buildexternaltext(params)
	local value = getvalue(params.value)
	if value and (type(value) == 'string') then
		externaltext = externaltext .. value
	end
end

function p.buildfooter(params)
	if not params then
		params = {}
	end
	
	local class = 'navbar noprint bordered ' .. (params.class or '')
	local style = params.style or {}
	style['border-top'] = style['border-top'] or '1px solid ' .. maincolor
	
	local backlinkstr = '[' .. tostring( mw.uri.fullUrl( page.name, 'veaction=edit&section=0' ) ) .. ' ' .. i18n['edit'] .. ']'
		.. ' - [' .. tostring( mw.uri.fullUrl( page.name, 'action=edit&section=0' ) ) .. ' ' .. i18n['edit code'] .. ']'

	local itemlinkstr
	if localdata.item then
		itemlinkstr = '[[d:' .. localdata.item.id .. '|' .. i18n['edit item'] .. ']]'
	end
	local editstr = backlinkstr
	if itemlinkstr then
		editstr = editstr .. ' - ' .. itemlinkstr
	end
	local editlinkspan =  mw.html.create('span')
		:css({['text-align'] = "left"})
		:addClass('plainlinks')
		:wikitext(editstr)
		:done()
	local doclinkstr = '[[Image:Info Simple.svg|12px|link=' .. localdata.templatename .. '|' .. i18n['see doc'] .. ']]'
	-- si ce lien ne marche pas toujours, il faut ajouter un variable pour le nom de l'infobox récupéré par le frame
	local doclinkspan = mw.html.create('span')
		:css({['text-align'] = "right"})
		:wikitext(doclinkstr)
		:done()
	
	local footer = mw.html.create('p')
		:addClass(class)
		:css(style)
		:node(editlinkspan)
		:node(doclinkspan)
	return footer
end

function p.buildblock(block)
	if type(block) == 'function' then
		block = block( localdata )
	end

	local blocktypes = { -- list of functions for block buildings
		['invalid'] = p.buildinvalidblock,
		['external text'] = p.buildexternaltext,
		['footer'] = p.buildfooter,
		['images'] = p.buildimages,
		['map']= p.buildmap,
		['mixed'] = p.buildrow,
		['navbox'] = p.buildnavbox,
		['table'] = p.buildtable,
		['row'] = p.buildrow,
		['row1col'] = p.buildrow1col,
		['succession'] = p.buildnavbox,
		['text'] = p.buildtext,
		['title'] = p.buildtitle,
	}
	if type(block) ~= 'table' or (not block.type) or (not blocktypes[block.type]) then
		return blocktypes['invalid'](block)
	end
	return blocktypes[block.type](block) 
end

function p.build()
	
	localdata = require( 'Module:Infobox/Localdata' )
	item = localdata.item

	-- assign rank to the infobox, "secondary" means special formatting like no displaytitle for coordinates
	local infoboxrank = 'main' -- main infobox of the page, with coordinates displayed in title etc.
	if page.namespace ~= 0 then
		infoboxrank = 'secondary'
	end
	-- if infobox is linked to another item: rank = secondary
	if localdata.item then
		local itemlink = mw.wikibase.sitelink(localdata.item.id)
		local pagetitle = mw.title.getCurrentTitle().text
		if (itemlink or '') ~= pagetitle then
			infoboxrank = 'secondary'
		end
	end
	localdata.infoboxrank = infoboxrank

	-- load infobox module page
	local moduledata = require('Module:Infobox/' .. localdata.modulename)
	moduledata.name = localdata.modulename
	-- defines main color
	maincolor = localdata['couleur infobox'] or localdata['couleur boîte'] or moduledata.maincolor or maincolor
	secondcolor =  moduledata.secondcolor or secondcolor
	thirdcolor =  moduledata.thirdcolor or thirdcolor
	if maincolor:match( '^%x%x%x%x%x%x$' ) or maincolor:match( '^%x%x%x$' ) then
		maincolor = '#' .. maincolor
	end
	
	-- class
	local class = 'infobox_v3'
	if moduledata.class then
		class = class .. ' ' .. moduledata.class
	end
	
	-- style
	local style = moduledata.style or {}
	if not style['max-width'] then
		style['max-width'] = '300px'
	end
	
	-- build infobox
	infobox	:addClass(class)
			:css(style)
	for i, j in pairs( moduledata.parts ) do
		infobox:node( p.buildblock(j) )
	end
	infobox	:node(p.buildfooter(moduledata.footer))
			:done()

	return tostring(infobox) .. externaltext, maintenance
end

return p