Module:Jumelages

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

 Documentation[voir] [modifier] [historique] [purger]

Module utilisé par le modèle {{Jumelages}}.

Utilisation[modifier le code]

Fonctions exportables :

  • tableauDesJumelages(frame) – Permet d'obtenir la liste des jumelages d'une ville / d'un village, ainsi qu'une carte interactive des villes jumelées.
local linguistic = require 'Module:Linguistique'
local wd = require 'Module:Wikidata'

local countryDataList = mw.loadData('Module:Country data/liste')

local p = {}

-- TODO: atdate
local function getFlag(entity, atdate, label, mediaName)
	local span = mw.html.create('span')
		:attr('data-sort-value', label)
	if not mediaName then
		local flagOrCOA = wd.getClaims({entity = entity,
			property = {'P41', 'P94'}, numval=1, atdate = atdate})  -- drapeau ou blason
		if flagOrCOA then
			mediaName = wd.formatStatement(flagOrCOA[1])
		end
	end
	if mediaName then
		span = span:wikitext('[[Fichier:' .. mediaName .. '|border|20x15px|class=noviewer]]')
	end
	return tostring(span:done())
end

local function getCity(statement)
	local entity = statement.mainId
	local label = statement.label
	local name = wd.formatStatement(statement, {showsource = true})
	local flag = getFlag(entity, 'today', label)
	return {flag, name or ''}
end

local function getCountryData(qid)
	-- On utilise Country data, qui permet d'obtenir "Chine" au lieu de
	-- "République de Chine" par exemple
	local countryKey = countryDataList[string.lower(qid)]
	if countryKey then
		local countryTable = require('Module:Country data/' .. countryKey)
		local name = countryTable and countryTable.name
		local flag, link, nameWithLink
		if name then
			if countryTable.flag then
				if type(countryTable.flag) == 'string' then
					flag = countryTable.flag
				elseif type(countryTable.flag.default) == 'string' then
					flag = countryTable.flag.default
				elseif type(countryTable.flag.default.default) == 'string' then
					flag = countryTable.flag.default.default
				end
			end
			if countryTable.link  then
				if type(countryTable.link) == 'string' then
					link = countryTable.link
				elseif type(countryTable.link.default ) == 'string' then
					link = countryTable.link.default
				end
			end
			if type(name) == 'string' then
				return name, flag, link
			end
			-- TODO: Period, utiliser bestfordate de Country data
			if name.default then
				return name.default, flag, link
			end
		end
	end
	return mw.wikibase.label(qid)
end

local function getCountry(statement)
	local entity = wd.getMainId(statement)
	-- TODO: changer atdate pour les jumelages terminés
	local country = wd.getClaims({entity = entity, property = 'P17',
		numval=1, atdate = 'today'})
	if country then
		local countryEntity = wd.getMainId(country[1])
		local name, flagFileName, link = getCountryData(countryEntity)
		local nameWithLink
		if name and link then
			nameWithLink = '[[' .. link .. '|' .. name .. ']]'
		else 
			nameWithLink = wd.formatEntity(countryEntity,
				{labelformat = function () return name end})
		end
		local flag = getFlag(countryEntity, 'today', name, flagFileName)
		return {flag, nameWithLink}
	end
end

local function getCoordinates(entity)
	local coord = wd.getClaims({entity = entity, property = 'P625',
		numval=1})
	if not coord then
		return
	end
	
	local snak = coord[1].mainsnak
	if snak.snaktype ~= 'value' then
		return
	end
	local value = snak.datavalue.value
	value.repr = value.latitude .. ', ' .. value.longitude
	return value
end

local function getPeriod(statement)
	return wd.getFormattedDate(statement)
end

local function getDefaultTitle(entity)
	local title = 'Jumelages et partenariats'
	local locationName = wd.getLabel(entity)
	if locationName then
		return title .. ' ' .. linguistic.of(locationName) .. '.'
	end
	return title .. '.'
end

local mapManager = {}

function mapManager.new(frame, args, title)
	local obj = {}
	
	local interactiveMapArgs = {
		zoom = args.zoom or 0,
		largeur = args['largeur carte'] or 420,
		hauteur = args['hauteur carte'] or 200,
		texte = title
	}
	
	local shouldCenterMap = interactiveMapArgs.zoom ~= 0
	local shapes = {}
	
	local latitudes = {}
	local longitudes = {}

	local function addLine(coordA, coordB)
		local line = frame:expandTemplate{title = 'Carte interactive/Ligne',
			args = {[1] = coordA.repr, [2] = coordB.repr, couleur = '#00bb00',
				opacity = .35
			}}
		table.insert(shapes, line)
	end

	function obj:addMarker(entity, coord, symbol, color, lineSource)
		coord = coord or getCoordinates(entity)
		if not coord then
			return
		end
		local locationName = wd.getLabel(entity)
		if not symbol and locationName then
			symbol = mw.ustring.lower(mw.ustring.sub(locationName, 1, 1))
			-- Seulement les symboles ASCII sont acceptés
			symbol = string.match(symbol, '%l')
		end
		local marker = frame:expandTemplate{title = 'Carte interactive/Marqueur',
			args = {[1] = coord.repr, title = locationName, symbol = symbol,
				couleur = color}}
		table.insert(shapes, marker)
		
		if shouldCenterMap then
			table.insert(latitudes, coord.latitude)
			table.insert(longitudes, coord.longitude)
		end
		
		if lineSource then
			addLine(coord, lineSource)
		end
	end
	
	local function centerPointSegment(points)
		if #points == 0 then
			return 0
		end
		return (math.min(unpack(points)) + math.max(unpack(points))) / 2
	end
	
	function obj:getMap()
		interactiveMapArgs.formes = table.concat(shapes, '\n')

		if shouldCenterMap then
			assert(#latitudes == #longitudes)
			interactiveMapArgs.latitude = centerPointSegment(latitudes)
			interactiveMapArgs.longitude = centerPointSegment(longitudes)
		else
			interactiveMapArgs.latitude = 0
			interactiveMapArgs.longitude = 0
		end
	
		return frame:expandTemplate{title = 'Carte interactive',
			args = interactiveMapArgs} 	
	end
	
	return obj
end

local function compareClaimLabels(c1, c2)
	return c1.sortKey < c2.sortKey
end

function p.tableauDesJumelages(frame)
	local args = frame:getParent().args
	
	-- Entité Wikidata
	local entity = wd.getEntity(args.wikidata)
	if not entity then
		error('Pas d\'entité Wikidata pour l\'élément.')
	end
	
	local showMap = not args.carte
		or string.lower(args.carte) ~= 'non'
	
	local twinCities = wd.getClaims({entity = entity,
		property = 'P190', rank = 'valid'})
	
	if not twinCities then
		return
	end
	-- Tri par nom de ville
	for _, twinCitie in ipairs(twinCities) do
		twinCitie.mainId = wd.getMainId(twinCitie)
		twinCitie.label = mw.wikibase.label(twinCitie.mainId)
		twinCitie.sortKey = mw.ustring.upper(twinCitie.label)
	end
	table.sort(twinCities, compareClaimLabels)
	
	local title = args.titre
		or getDefaultTitle(entity)
		
	-- Bouton d'édition Wikidata
	title = wd.addLinkBack(title, entity, 'P190')

	local tab = mw.html.create('table')
		:addClass('wikitable')
		:addClass('centre')
		:addClass('sortable')
		:addClass('alternance')
		:node('<caption>' .. title .. '</caption>') --titre
	
	local columns = {
		{fn = getCity, colName = 'Ville', withFlag = 1},
		{fn = getCountry, colName = 'Pays', withFlag = 1},
    	{fn = getPeriod, colName = 'Période'}
	}
	
	local data = {}
	for _, statement in ipairs(twinCities) do
		local cityData = {}
		for _, column in ipairs(columns) do
			local _, value = pcall(column.fn, statement)
			table.insert(cityData, value
				or (column.withFlag and {'', ''})
				or '')
			if value and not column.hasValues then
				column.hasValues = true
			end
		end
		table.insert(data, cityData)
	end

	local tr = mw.html.create('tr')
	for _, column in pairs(columns) do
		if column.hasValues then
			local th = mw.html.create('th')
				:attr('scope', 'col')
				:wikitext(column.colName)
			if column.withFlag then
				th = th:attr('colspan', 2)
			end
			tr = tr:node(th:done())
		end
	end
	tab = tab:node(tr:done())
	
	for _, cityData in ipairs(data) do
		local tr = mw.html.create('tr')
		for j, column in pairs(columns) do
			if column.hasValues then
				local value = cityData[j]
				if column.withFlag then
					tr = tr:node(mw.html.create('td')
						:css('border-right', 0)
						:wikitext(value[1] or ''):done())
					tr = tr:node(mw.html.create('td')
						:css('border-left', 0)
						:wikitext(value[2] or ''):done())
				else
					tr = tr:node(mw.html.create('td')
						:wikitext(value or ''):done())
				end
			end
		end
		tab = tab:node(tr:done())
	end
	
	tab = tostring(tab:done())
	
	if not showMap then
		return tab
	end
	
	local cityMapManager = mapManager.new(frame, args, title)
	
	local mainCoordinates = getCoordinates(entity)
	if mainCoordinates then
		cityMapManager:addMarker(entity, mainCoordinates, 'star', '#00bb00',
			nil)
	end
	
	for _, statement in ipairs(twinCities) do
		local twinQid = statement.mainId
		cityMapManager:addMarker(twinQid, nil, nil, nil, mainCoordinates)
	end
	
	return cityMapManager:getMap() .. tab
end

return p