Module:Composition Division de France

Une page de Wikipédia, l'encyclopédie libre.

 Documentation[créer] [purger]
local p = {}

local PopulationFrance = require 'Module:Population de France/Données'
local Unite = require 'Module:Unité'

local lang = mw.getContentLanguage()
local charte = 'default'
local configData = {
	default = {
		titreTableau = ' ',
		selectCapitale = '(siège)',
		colonnes = { 'intercommunalité' },
		couleurEntete = '#f2f2f2',
		insee = 'P374'
	},
	['aire urbaine'] = {
		titreTableau = 'de l\'aire urbaine',
		selectCapitale = '(ville-centre)',
		colonnes = { 'département' },
		couleurEntete = '#ece5ca',
	},
	['aav'] = {
		titreTableau = 'de l\'aire d\'attraction',
		selectCapitale = '(commune-centre)',
		colonnes = { 'département', 'statut_AAV2020' },
		couleurEntete = '#ece5ca',
	},
	['arrondissement'] = {
		titreTableau = 'de l\'arrondissement',
		selectCapitale = '(chef-lieu)',
		couleurEntete = '#e1e1e1',
		insee = 'P3423',
	},
	['canton'] = {
		titreTableau = 'du canton',
		selectCapitale = '(bureau centralisateur)',
		couleurEntete = '#ece5ca',
		insee = 'P2506'
	},
	['département'] = {
		titreTableau = 'du département',
		selectCapitale = '(préfecture)',
		colonnes = { 'code postal', 'arrondissement', 'canton', 'intercommunalité' },
		couleurEntete = '#f6f3dd',
		insee = 'P2586'
	},
	['intercommunalité'] = {
		titreTableau = 'de l\'intercommunalité',
		colonnes = { 'département', 'gentilé' },
		couleurEntete = '#ffe2bf',
		insee = 'P1616',
	},
	['localité'] = {
		titreTableau = 'de la localité'
	},
	['circonscription'] = {
		titreTableau = 'de la circonscription',
		couleurEntete = '#ece5ca'
	},
	['commune nouvelle'] = {
		titreTableau = ' historiques',
		colonnes = { 'code postal' },
		couleurEntete = '#ddffdd',
	},
	['métropole'] = {
		titreTableau = 'de la métropole',
		colonnes = { 'gentilé' },
		couleurEntete = '#f6f3dd',
	},
	['région'] = {
		titreTableau = 'de la région',
		selectCapitale = '(préfecture)',
		colonnes = { 'département'},
		couleurEntete = '#bbdefd',
		insee = 'P2585',
	},
	['unité urbaine'] = {
		titreTableau= 'de l\'unité urbaine',
		selectCapitale = '(ville-centre)',
		colonnes =  { 'département', 'statut_UU2020' },
		couleurEntete = '#ece5ca',
	},
	['pays'] = {
		titreTableau = ' ',
		selectCapitale = '(capitale)',
		colonnes = { 'région', 'département' },
		couleurEntete = '#f2f2f2',
	},
}

local function config( param, liste )
	if liste and param == 'colonnes' and liste:lower() ~= 'communes' then
		return {}
	else
		return configData[ charte ][ param ] or configData.default[ param ]
	end
end

local function abbr( abrev, description )
	local wiki = mw.html.create( 'abbr' )
		:addClass( 'abbr')
		:attr{ title = description }
		:wikitext( abrev )
	return wiki
end

local function getValue( t, v, ... )
	if v and type(t) == 'table' then
		return getValue( t[v], ... )
	elseif v then
		return nil
	else
		return t
	end
end
p.getValue = getValue

local aliasTableCommons = {
	['département'] = 'dep',
	['région'] = 'region',
	['canton'] = 'cv',
	['arrondissement'] = 'arr',
	['intercommunalité'] = 'epci',
	['insee'] = 'code',
	['AAV'] = 'AAV2020',
	['unité urbaine'] = 'UU2020',
}

local function getCommonsData( name )
	name = 'Table/' .. lang:ucfirst( name ) .. '.tab'
	return mw.ext.data.get( name, '_' )
end
local function findCommonsColumn( json, name )
	name = mw.ustring.lower( name )
	name = aliasTableCommons[ name ] or name
	for i, v in ipairs( json.schema.fields ) do
		if v.name == name then
			return i
		end
	end
end
local function findCommonsData( json, name, value )
	local column = findCommonsColumn( json, name )
	for i, v in ipairs( json.data ) do
		if v[ column ] == value then
			return json.data[ i ]
		end
	end
end
local function findCommonsDataSet( json, name, value, list )
	local column = findCommonsColumn( json, name )
	list = list or {}
	for i, v in ipairs( json.data ) do
		if v[ column ] == value then
			table.insert( list, json.data[ i ] )
		end
	end
	return list
end
local function getCommonsValue( json, name1, value1, name2 )
	local data = findCommonsData( json, name1, value1 )
	local column = findCommonsColumn( json, name2 )
	return data and data[ column ]
end

--[[ Normalisation qui retire les diacritiques
     pour le tri alphabétique ]]--
     
local tableAccents = {

    ['à'] = 'a',
    ['â'] = 'a',
    ['ç'] = 'c',
    ['è'] = 'e',
    ['é'] = 'e',
    ['ê'] = 'e',
    ['ë'] = 'e',
    ['î'] = 'i',
    ['ï'] = 'i',
    ['ô'] = 'o',
    ['ù'] = 'u',
    ['û'] = 'u',
    ['ü'] = 'u',
    ['À'] = 'A',
    ['Â'] = 'A',
    ['Ç'] = 'C',
    ['È'] = 'E',
    ['É'] = 'E',
    ['Ê'] = 'E',
    ['Ë'] = 'E',
    ['Î'] = 'I',
    ['Ï'] = 'I',
    ['Ô'] = 'O',
    ['Ù'] = 'U',
    ['Û'] = 'U',
    ['Ü'] = 'U',
    ['œ'] = 'oe',
    ['Œ'] = 'Oe'
}

local function normalise( str )
	-- Solution inspirée de http://lua-users.org/wiki/LuaUnicode
	-- La regex utilisée est plus spécifique et balaye uniquement les séquences décimales UTF-8 
	-- des [[diacritiques utilisés en français]] latins
	-- voir tableau https://www.utf8-chartable.de/unicode-utf8-table.pl?utf8=dec&unicodeinhtml=dec&htmlent=1
	local normalised = str:gsub( '[%z\197][\146-\147]', tableAccents ):gsub( '[%z\195][\128-\191]', tableAccents )

	return normalised 
end

local function removeColumn(tab, column)
	for i, v in ipairs( tab ) do
		if tab[ i ] == column then
			table.remove(tab, i)
			return tab
		end
	end
end

--------------------------------------

function p.getList( args )
	if args.debug then
		charte = args.charte
	end
	if charte == 'default' or not args[ charte ] then
		mw.log 'pas de charte'
		return
	end
	local dataDivisions = getCommonsData( charte .. 's' ) 
	local id = mw.wikibase.getEntityIdForTitle( lang:ucfirst( args[ charte ] ) )
	if not ( id and dataDivisions ) then
		mw.log( "pas d'id ou de table " .. charte .. 's' )
		return
	end
	local inseeProp = mw.wikibase.getBestStatements( id, config( 'insee' ) )
	local insee = args.insee or getValue( inseeProp, 1, 'mainsnak', 'datavalue', 'value' )
	
	if (args[ charte ] == "Mayotte") then -- L'article principal de Mayotte n'a pas le même id Wikidata (Q17063) que le département de Mayotte (Q124284929)
		insee = '976'
	end
	args.insee = insee
	if not ( insee ) then
		mw.log 'pas de code insee'
		return
	end
	
	-- donnée sur les divisions de la chartes
	local dataDivision = findCommonsData( dataDivisions, 'code', insee )
	if not dataDivision then
		mw.log 'pas de donnée sur cette division'
		return
	end
	
	-- trouve la liste de divisions
	local nomRegion = { '' }
	local codeChef
	args['liste de'] = ( args['liste de'] or 'communes' ):lower()
	local listNomCommonsData = { args['liste de'] }
	if args['liste de'] == 'communes' then
		codeChef = dataDivision[ findCommonsColumn( dataDivisions, 'capitale' ) ]
		-- trouve la région
		local regions = getCommonsData 'Régions'
		local codeRegion = dataDivision[ findCommonsColumn( dataDivisions, 'région' ) ]
		listNomCommonsData = {}
		for code in mw.text.gsplit( codeRegion, ', ?' ) do
			table.insert( 
				listNomCommonsData, 
				'Communes ' .. getCommonsValue( regions, 'code', code, 'name' )
			)
		end
	end
	local completeList, list
	for _, nomCommonsData in ipairs( listNomCommonsData ) do 
		completeList = getCommonsData( nomCommonsData )
		if not completeList then
			mw.log( 'pas de liste de sous-divisions « ' .. nomCommonsData .. ' »' )
			return
		end
		list = findCommonsDataSet( completeList, charte, insee, list )
	end
	if charte == 'canton'
		and args['liste de']:lower() == 'communes'
		and dataDivision[ findCommonsColumn( dataDivisions, 'typct' ) ] ~= 1
	then
		fractions = require 'Module:Données/Fractions cantonales/évolution population'.parCodeCanton[ insee ]
		if fractions then
			args.fraction = true
			for i, v in ipairs( fractions ) do
				table.insert( list, findCommonsData( completeList, 'code', v.codeCommune ) )
			end
		end
	end
	
	-- tri et définition des paramètres
	local idColumn = findCommonsColumn( completeList, 'qid' )
	local codeColumn = findCommonsColumn( completeList, 'code' )
	local nccColumn = findCommonsColumn( completeList, 'ncc' )
	local listeCommunes = {}
	for i, v in ipairs( list ) do
		local id = v[ idColumn ]
		if v[ codeColumn ] == codeChef then
			args['chef-lieu'] = mw.wikibase.getSitelink( id )
		else
			local commune = { titre = true, cleTri = true }
			commune.titre = mw.wikibase.getSitelink( id )
			if args['liste de'] == 'communes' then
				commune.cleTri = v[ nccColumn ]            -- Le NCC n'existe que pour les communes
			else
				commune.cleTri = normalise( commune.titre ) -- Pour les autres divisions, on utilise la normalisation des diacritiques
			end
			table.insert( listeCommunes , commune )
		end
	end
	table.sort( listeCommunes,  function( a, b ) return a.cleTri < b.cleTri end )
	for i, v in ipairs( listeCommunes ) do
		args[ 'commune ' .. i ] = v.titre
	end
	
	-- début du titre, avec vérification que la liste est complète
	local titre
	if args['liste de'] == 'communes' then
		local nbCom = tonumber( dataDivision[ findCommonsColumn( dataDivisions, 'nbcom' ) ] )
		if nbCom and nbCom == #list then
			if #list ==1 then
				if charte == 'canton'
					and tonumber( dataDivision[ findCommonsColumn( dataDivisions, 'typct' ) ] ) >= 4 then
					titre = 'Liste de la fraction'
				else
					titre = 'Liste de la commune'
				end
			else
				titre = 'Liste des ' .. nbCom .. ' communes'
				args.exhaustif = true
			end
		else
			titre = 'Liste partielle des communes'
			mw.log( 'nombre de commune attendues : ', nbCom )
			mw.log( 'nombre de commune dans la liste : ', #list )
		end
	else
		titre = 'Liste des ' .. args['liste de']
	end
	
	-- poursuite du titre
	local nomDivision = mw.wikibase.getLabel( id )
	local test, moduleCarte = pcall( require, 'Module:Carte/données/' .. mw.ustring.lower( nomDivision ) )
	if test and moduleCarte.genre then
		local genreTab = require 'Module:Drapeau/Domaine'.genre
		local genre = genreTab[ moduleCarte.genre:gsub( '[ME]', '' ):gsub( '\'', 'a' ) ] or { du = '' }
			if charte == 'région' then -- on ne met pas de genre devant la région pour éviter "de la région de l'Île-de-France"
				nomDivision = nomDivision 
			else
				nomDivision = genre.du .. nomDivision 
			end
	else
local String
		nomDivision = mw.ustring.gsub(nomDivision, " [(][^()]*[)]$", "") -- retire le contenu des parenthèses dans le titre (homonymie)
		-- nomDivision = args[ charte ]:gsub( ' %(' .. charte .. '%)$', '' ) -- ne retire le contenu des parenthèses que s'il contient la charte
	end
	titre = titre
		.. ' '
		.. config( 'titreTableau' )
		.. ' '
		.. nomDivision
		.. ' au '
		.. require 'Module:Date'.modeleDate{ completeList.description.date, nolinks=true }
		
	args.titre = titre	:gsub( '\'intercommunalité Communauté', 'la communauté' )
		:gsub( '\'intercommunalité [Mm]étropole', 'la métropole' )
		:gsub( '\'arrondissement [Aa]rrondissement', '\'arrondissement')
		:gsub( 'canton [Cc]anton', 'canton')  
		:gsub( 'de La ', 'de la ')  
		:gsub( 'de L\'', 'de l\'')  
		:gsub( 'du département [Cc]irconscription', 'de la circonscription')  
		:gsub( 'du département de la Guadeloupe', 'de la Guadeloupe')  
		:gsub( 'du département de la Martinique', 'de la Martinique')  
		:gsub( 'du département de la Guyane', 'de la Guyane')  
		:gsub( 'du département de [Ll]a Réunion', 'de La Réunion')  


	return args
end

local function getData( division )
	if not division or division == '' then
		return nil
	end
	local data, existe = PopulationFrance.charge_donnees( division )
	if existe == true or existe > 2 then
		data.page = division
		data.population = data.dernier and data[ data.dernier ].pop
		if data.superficie == -1 then                     -- on n'affiche pas la superficie (il y a des communes qui ont une superficie de 1.00, d'où -1)
			data.superficie = nil
		end
        if data.division == "canton" and data.superficie == 1 then  -- rétrocompatibilité
			data.superficie = nil
		end
		if data.superficie and data.population then
			data.densite = data.population / data.superficie
			local prec = 1 - math.floor( math.log10( data.densite ) )
			data.precisionDensite = math.min( 2, math.max( 0, prec ) )
		end
		return data
	end
end


function p.tableau( args )
	local testCharte = mw.ustring.lower( args.charte or '' )
	if configData[ testCharte ] then
		charte = testCharte
	end
	
	-- liste
	if not (args[ 'commune 1' ] or args[ 'commune 2' ]) then
		p.getList( args )
	end
	
	-- récupération des données
	local dataCommunes = {}
	local dataDivision = getData( args[ charte ] )
	local fractions
	local superficieTotale, populationTotale, datePop = 0, 0
	if charte == 'canton' then
		fractions = require 'Module:Données/Fractions cantonales/évolution population'
	end
	local chef = getData( args['chef-lieu'] or args['bureau'] )
	if chef then
		chef.selectCapitale = config( 'selectCapitale' )
		chef.canton = fractions and fractions.parCommune[ chef.page ] or chef.canton
		table.insert( dataCommunes, chef )
	end
	for i = 1, 891 do
		local nomCommune = args[ 'commune ' .. i ]
		if nomCommune and nomCommune ~= '' then
			local commune = getData( nomCommune )
			if commune then
				commune.canton = fractions and fractions.parCommune[ nomCommune ] or commune.canton
				table.insert( dataCommunes, commune )
			else
				table.insert( dataCommunes, nomCommune )
			end
		end
	end
	local colonnes = config( 'colonnes', args['liste de'] )
	
	if (args[ charte ] == "Mayotte") then -- Pas d'arrondissement à Mayotte
		removeColumn( colonnes, "arrondissement")
	end
	if (args[ charte ] == "Guyane" or args[ charte ] == "Martinique") then -- Pas de canton en Guyane et en Martinique
		removeColumn( colonnes, "canton")
	end
	-- construction du tableau
	local wiki = mw.html.create()
	-- entête
	wiki:newline()
		:wikitext( '{| class="wikitable sortable titre-en-couleur" align="center" style="text-align:center;"' )
		:newline()
		:wikitext( '|+ ', args.titre or 'Liste des communes ' .. config( 'titreTableau' ) .. ( args.autre or '' ) )
		:newline()
		:wikitext( '|- style="background:', config( 'couleurEntete' ), ';"' )
		:newline()
		:wikitext( '! scope="col" | Nom' )
		:newline()
		:wikitext( '! scope="col" | Code' )
		:tag( 'br' ):done()
		:node( abbr( 'Insee', 'Institut national de la statistique et des études économiques' ) )
	
	for _, colonne in ipairs( colonnes ) do
		local nomColonne = colonne :gsub( '[Ss]tatut_UU2020', 'Statut' )
				:gsub( '[Ss]tatut_AAV2020', 'Statut' )
		if type( colonne ) == 'table' then
			nomColonne = colonne.titre
		end
		wiki:newline()
			:wikitext( '! scope="col" | ', lang:ucfirst( nomColonne ) )
	end
	
	wiki:newline()
		:wikitext( '! scope="col" | Superficie' )
		:tag( 'br' ):done()
		:tag( 'small' )
			:node( abbr( '(km<sup>2</sup>)', 'kilomètres carrés' ) )
		:done()
		:newline()
		:wikitext( '! scope="col" data-sort-type="number" | Population' )
		:tag( 'br' ):done()
		:tag( 'small' )
			:addClass( 'nowrap' )
			:wikitext( '(dernière [[Recensement de la population en France#Décomposition de la population légale depuis 2009|' )
			:node( abbr( 'pop. légale', 'population légale' ) )
			:wikitext( ']])')
		:done()
		:newline()
		:wikitext( '! scope="col" data-sort-type="number" | Densité' )
		:tag( 'br' ):done()
		:tag( 'small' )
			:addClass( 'nowrap' )
			:node( abbr( '(hab./km<sup>2</sup>)', 'habitants par kilomètre carré' ) )
		:done()
		:newline()
		:wikitext( '! scope="col" class="unsortable" | Modifier' )
	
	-- Lignes
	local frame = mw.getCurrentFrame()
	for i, commune in ipairs( dataCommunes ) do
		wiki:newline()
			:wikitext( '|-' )
			:newline()
			:wikitext( '| style="text-align:left;" | ' )
			
		if type( commune ) == 'table' then
			local nomModele = 'Données/' .. commune.page .. '/informations générales'
			local utilisationModele = false
			if commune.selectCapitale then
				wiki:wikitext( "'''", commune['nom-wp'], "'''" )
					:tag( 'br' ):done()
					:tag( 'small' )
						:wikitext( commune.selectCapitale )
					:done()
			else
				wiki:wikitext( commune['nom-wp'] )
			end
			
			superficieTotale = superficieTotale + (commune.superficie or 0)
			populationTotale = populationTotale + (commune.population or 0)
			if datePop == nil then
				datePop = commune.dernier
			elseif datePop ~= commune.dernier then
				args.exhaustif = false
			end
			
			wiki:newline()
				:wikitext( '| ' )
				:wikitext( commune.insee )
			
			for _, colonne in ipairs( colonnes ) do
				local nomColonne = colonne
				if type( colonne ) == 'table' then
					nomColonne = colonne.source
				end
				local dataColonne, test = commune[ nomColonne ]
				if not dataColonne then
					test, dataColonne = pcall(
						frame.expandTemplate,
						frame,
						{ title = nomModele, args = { nomColonne } }
					)
					if test then
						utilisationModele = true
					else
						dataColonne = ''
					end
				elseif type( dataColonne ) == 'table' then
					if type( dataColonne[1] ) == 'table' then
						local tempDataColonne = {}
						for _, v in ipairs( dataColonne ) do
							table.insert( tempDataColonne, v['canton-wp'] )
						end
						dataColonne = tempDataColonne
					end
					dataColonne = table.concat( dataColonne, '<br>' )
				end
				wiki:newline()
					:wikitext( '| ' )
					:wikitext( dataColonne )
			end
			
			wiki:newline()
				:wikitext( '| ' )
				:wikitext( Unite._unite{ commune.superficie, ['décimales'] = 2 } )
				:newline()
				:wikitext( '| ' )
			if commune.population then
				local fraction
				if charte == 'canton' and type( commune.canton ) == 'table' then
					for _, c in ipairs( commune.canton ) do
						if c.canton == mw.title.getCurrentTitle().text or c.canton == args.canton then
							fraction = c
							break
						end
					end
				end
				if fraction then
					populationTotale = populationTotale - commune.population + fraction.pop
					wiki:wikitext( 'Fraction : ', Unite._unite{ fraction.pop }, ' ' )
						:tag( 'small' )
							:wikitext( '(' ..fractions.dateDonnees .. ')' )
						:done()
						:tag( 'br' ):done()
						:tag( 'small' )
							:wikitext( 'Commune : ', Unite._unite{ commune.population }, ' ' )
							:tag( 'small' )
								:wikitext( '(' ..commune.dernier .. ')' )
							:done()
						:done()
				else
					-- l'attribut data-sort-value permet un triage sur une
					-- valeur spécifique pour éviter de prendre en compte l'année
					wiki:wikitext( 'data-sort-value="', commune.population, '" | ')
						:wikitext( Unite._unite{ commune.population }, ' ' )
						:tag( 'small' )
							:wikitext( '(' ..commune.dernier .. ')' )
						:done()
				end
			end
			wiki:newline()
				:wikitext( '| ' )
				:wikitext( Unite._unite{ commune.densite, ['décimales'] = commune.precisionDensite } )
				:newline()
				:wikitext( '| ' )
				:wikitext( '[[File:Blue pencil.svg|modifier les données|10px|baseline|class=noviewer|link=' .. commune.module .. ']]' )
			if utilisationModele then
				wiki:wikitext( '&emsp;[[File:Green pencil.svg|modifier les données|10px|baseline|class=noviewer|link=Modèle:' .. nomModele .. ']]' )
			end
		
		else
			args.exhaustif = false
			wiki:wikitext( commune )
				:newline()
				:wikitext( '| ' )
				:tag( 'span' )
					:css{ color = 'red' }
					:wikitext( '????' )
					:wikitext( '[[Catégorie:Article avec modèle Composition Division de France erroné]]' )
				:done()
				:newline()
				:wikitext( '|' )
			for i = 1, 3 + #colonnes do
				wiki:wikitext( ' ||' )
			end
		end
	end


	-- ligne pour la division
	if not dataDivision and args.exhaustif then
		dataDivision = {
			insee = args.insee,
			['nom-wp'] = args[ charte ],
			population = populationTotale,
			dernier = datePop,
		}
	end
	if dataDivision then
		if not dataDivision.superficie and args.exhaustif and not args.fraction and populationTotale == dataDivision.population then
			dataDivision.superficie = superficieTotale
			dataDivision.densite = populationTotale / superficieTotale
			local prec = 1 - math.floor( math.log10( dataDivision.densite ) )
			dataDivision.precisionDensite = math.min( 2, math.max( 0, prec ) )
		end
		wiki:newline()
			:wikitext( '|- style="background:', config( 'couleurEntete' ), ';"' )
			:newline()
			:wikitext( '! scope="row" | ' )
			:wikitext( dataDivision['nom-wp'] )
			:newline()
			:wikitext( '! ' )
			:wikitext( dataDivision.insee )
		for _, colonne in ipairs( colonnes ) do
			wiki:newline()
				:wikitext( '! ' )
		end
		wiki:newline()
			:wikitext( '! ' )
			:wikitext( Unite._unite{ dataDivision.superficie, ['décimales'] = 2 } )
			:newline()
			:wikitext( '! ' )
		if dataDivision.population then
			wiki:wikitext( Unite._unite{ dataDivision.population }, ' ' )
				:tag( 'small' )
					:wikitext( '(' ..dataDivision.dernier .. ')' )
				:done()
		end
		wiki:newline()
			:wikitext( '! ' )
			:wikitext( Unite._unite{ dataDivision.densite, ['décimales'] = dataDivision.precisionDensite } )
			:newline()
			:wikitext( '! ' )
		if dataDivision.module then
			wiki:wikitext( '[[File:Blue pencil.svg|modifier les données|10px|baseline|class=noviewer|link=' .. dataDivision.module .. ']]' )
		end
			
	end
	
	-- fin du tableau
	wiki:newline()
		:wikitext( '|}' )
		:wikitext( '[[Catégorie:Article avec modèle Composition Division de France]]' )
	
	return tostring( wiki )
end

p["modèle"] = function( frame )
	local args = frame.getParent and frame:getParent().args
	if args then
		return p.tableau( args )
	end
	return ""
end

return p