Module:Carte interactive

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

local p = {}
local coord = require( "Module:Coordinates" )

local function normalise(args)
	local lookup_table = {
		['largeur'] = 'width',
		['hauteur'] = 'height',
		['texte'] = 'text',
		['legende'] = 'text',
		['légende'] = 'text',
		['déscription'] = 'description',
		['titre'] = 'title',
		['sans_cadre'] = 'frameless',
		['symbole'] = 'symbol',
		['couleur'] = 'color',
		['taille'] = 'size',
		['epaisseur'] = 'size',
		['épaisseur'] = 'size',
		['opacite'] = 'opacity',
		['opacité'] = 'opacity',
		['epaisseur contour'] = 'outline_size',
		['épaisseur contour'] = 'outline_size',
		['couleur contour'] = 'outline_color',
		['opacite contour'] = 'opacity',
		['opacité contour'] = 'opacity',
		['couleur fond'] = 'fill_color',
		['opacite fond'] = 'fill_opacity',
		['opacité fond'] = 'fill_opacity',
		['geoline'] = 'contour',
		['requête'] = 'query',
		['requete'] = 'query',
		['request'] = 'query',
		['langue'] = 'lang',
	}
	
	for k, v in pairs(lookup_table) do
		if args[k] ~= nil then
			args[v] = args[k]
		end
	end
	
	return args
end

local function decodeJsonList(value)
	--[[ Plusieurs modèles, dont {{Carte interactive/Marqueur}}, ajoutent des
	virgules à la fin des représentations JSON des objets. Cela fonctionne avec
	le parsing JSON relaxé de HHVM, mais pas PHP7. Ce bug est détaillé ici:
		https://phabricator.wikimedia.org/T214984
	Cette fonction retire donc les virgules finales et initiales, avant
	d'appeler mw.text.jsonDecode sur la liste.
	]]
	local trimmedValue = mw.text.trim(value, ',')
	return mw.text.jsonDecode('[' .. trimmedValue .. ']')
end

function p.marker(frame)
	local args = normalise(frame:getParent().args)
	
	if args[1] == nil and args.latlng == nil then --One coordinate is mandatory
		return
	end
	
	local properties = {
		['marker-color'] = args.color == nil and '#555555' or args.color,
		['marker-size'] = args.size == nil and 'medium' or args.size,
		['marker-symbol'] = args.symbol == nil and '' or args.symbol,
		['title'] = args.title == nil and '' or args.title,
		['description'] = args.description == nil and '' or args.description,
	}
	
	local latlng = mw.text.split( (args[1] == nil and args.latlng or args[1]), ",", true )
	
	if args.randomise ~= nil then
		latlng[1] = latlng[1] + math.random(-tonumber(args.randomise), tonumber(args.randomise))/100000
		latlng[2] = latlng[2] + math.random(-tonumber(args.randomise), tonumber(args.randomise))/100000
	end
	
	local geojson = {
            type = "Feature",
            properties = properties,
            geometry = {
                type = "Point",
                coordinates = {
                	tonumber(latlng[2]), 
                	tonumber(latlng[1]),
                }
            }
        }
    return mw.text.jsonEncode(geojson) .. ','
end

function p.line(frame)
	local args = normalise(frame:getParent().args)
	
	if args[2] == nil then --At least two coordinates are mandatory
		return
	end
	
	local properties = {
		["stroke"] = args.color == nil and '#555555' or args.color,
		["stroke-width"] = args.size == nil and 2 or tonumber(args.size),
		["stroke-opacity"] = args.opacity == nil and 1 or tonumber(args.opacity),
		['title'] = args.title == nil and '' or args.title,
		['description'] = args.description == nil and '' or args.description,
	}
	
	local coordinates = {}
	local i = 1
	while args[i] ~= nil do
		local latlng = mw.text.split( args[i], ",", true )
		coordinates[i] = {
        	tonumber(latlng[2]), 
        	tonumber(latlng[1]),
        }
		i = i+1
	end
	
	local geojson = {
            type = "Feature",
            properties = properties,
            geometry = {
                type = "LineString",
                coordinates = coordinates
            }
        }
    return mw.text.jsonEncode(geojson) .. ','
end

function p.polygon(frame)
	local args = normalise(frame:getParent().args)
	
	if args[3] == nil then --At least three coordinates are mandatory
		return
	end
	
	local properties = {
		["stroke"] = args.color == nil and '#555555' or args.color,
		["stroke-width"] = args.size == nil and 2 or tonumber(args.size),
		["stroke-opacity"] = args.opacity == nil and 1 or tonumber(args.opacity),
		["fill"] = args.fill_color == nil and '#555555' or args.fill_color,
		["fill-opacity"] = args.fill_opacity == nil and 0.3 or tonumber(args.fill_opacity),
		['title'] = args.title == nil and '' or args.title,
		['description'] = args.description == nil and '' or args.description,
	}
	
	local coordinates = {}
	local i = 1
	while args[i] ~= nil do
		local latlng = mw.text.split( args[i], ",", true )
		coordinates[i] = {
        	tonumber(latlng[2]), 
        	tonumber(latlng[1]),
        }
		i = i+1
	end
	local latlng = mw.text.split( args[1], ",", true )
	coordinates[i] = {
    	tonumber(latlng[2]), 
    	tonumber(latlng[1]),
    }
	
	local geojson = {
            type = "Feature",
            properties = properties,
            geometry = {
                type = "Polygon",
                coordinates = { coordinates }
            }
        }
    return mw.text.jsonEncode(geojson) .. ','
end

function p.query(frame)
	local args = normalise(frame:getParent().args)
	
	local query
	if args[1] ~= nil then
		query = args[1]
	else
		return
	end
	
	local properties = {
		["stroke"] = args.color == nil and '#555555' or args.color,
		["stroke-width"] = args.size == nil and 2 or tonumber(args.size),
		["stroke-opacity"] = args.opacity == nil and 1 or tonumber(args.opacity),
		["fill"] = args.fill_color == nil and '#555555' or args.fill_color,
		["fill-opacity"] = args.fill_opacity == nil and 0.3 or tonumber(args.fill_opacity),
		['title'] = args.title == nil and '' or args.title,
		['description'] = args.description == nil and '' or args.description,
	}
	
	local service = "geoshape"
	if args.contour ~= nil then
		service = "geoline"
	end
	
	local geojson = {
		type = "ExternalData",
		service = service,
		query = query,
		properties = properties,
	}
    return mw.text.jsonEncode(geojson) .. ','
end

function p.osm(frame)
	local args = normalise(frame:getParent().args)
	
	local qid
	if args[1] == nil then
		qid = mw.wikibase.getEntityIdForCurrentPage()
	else
		qid = mw.text.trim(args[1])
	end
	
	local properties = {
		["stroke"] = args.color == nil and '#555555' or args.color,
		["stroke-width"] = args.size == nil and 2 or tonumber(args.size),
		["stroke-opacity"] = args.opacity == nil and 1 or tonumber(args.opacity),
		["fill"] = args.fill_color == nil and '#555555' or args.fill_color,
		["fill-opacity"] = args.fill_opacity == nil and 0.3 or tonumber(args.fill_opacity),
		['title'] = args.title == nil and '' or args.title,
		['description'] = args.description == nil and '' or args.description,
	}
	
	local service = "geoshape"
	if args.contour ~= nil then
		service = "geoline"
	end
	
	local geojson = {
		type = "ExternalData",
		service = service,
		ids = qid,
		properties = properties,
	}
    return mw.text.jsonEncode(geojson) .. ','
end

function p.commons(frame)
	local args = normalise(frame:getParent().args)
	
	if args[1] == nil then
		return
	end
	
	local page_name = args[1]
	if mw.ustring.find(page_name, "Data:", 1, true) == 1 then
		page_name = string.sub(page_name, 6)
	end
	if mw.ustring.find(page_name, ".map", -4, true) == nil then
		page_name = page_name .. '.map'
	end
	
	local geojson = {
		type = "ExternalData",
		service = "page",
		title = page_name
	}
    return mw.text.jsonEncode(geojson) .. ','
end

function p.wikidata(frame)
	local args = normalise(frame:getParent().args)
	local qid
	
	local properties = {
		['marker-color'] = args.color == nil and '#555555' or args.color,
		['marker-size'] = args.size == nil and 'medium' or args.size,
		['marker-symbol'] = args.symbol == nil and '' or args.symbol,
		['title'] = args.title == nil and '' or args.title,
		['description'] = args.description == nil and '' or args.description,
	}
	
	if args[1] == nil then
		qid = mw.wikibase.getEntityIdForCurrentPage()
	else
		qid = args[1]
	end
	
	local entity = mw.wikibase.getEntity( qid )
	local value = entity:formatPropertyValues( 'P625', { mw.wikibase.entity.claimRanks.RANK_NORMAL, mw.wikibase.entity.claimRanks.RANK_PREFERRED, mw.wikibase.entity.claimRanks.RANK_TRUTH } ).value
	if value == nil then
		error('La propriété P625 "coordonnées géographiques" n\'est pas renseigné sur Wikidata')
	end
	latlng = mw.text.split( mw.text.decode(value), ", ", true )
	geojson = {
		type = "Feature",
		geometry = {
			type = "Point",
			coordinates = {
				coord._dms2dec(coord._parsedmsstring(latlng[2])), 
				coord._dms2dec(coord._parsedmsstring(latlng[1]))
			}
		},
		properties = properties
	}
	
	return mw.text.jsonEncode(geojson) .. ','
end

function p.tag(frame)
    local args = ( frame.getParent and normalise(frame:getParent().args) ) or frame
	
	-- Choose the tagname
	local tagname = 'mapframe'
	if args.lien ~= nil then
		tagname = 'maplink'
	end

	-- Manage the basics tag params
	local tagArgs = {
		zoom = args.zoom == nil and args.commons == nil and 14 or tonumber(args.zoom),
		height = args.height == nil and 420 or tonumber(args.height),
		width = args.width == nil and 420 or tonumber(args.width),
		align = args.align == nil and 'right' or args.align,
		text = args.text,
	}
	
	if args[1] ~= nil and (args.latitude ~= nil or args.longitude ~= nil) then
		error('La ou les valeurs de longitude et/ou de latitude ont été fournis via deux syntaxe différentes. Consultez la documentation du [[Modèle:Carte interactive]] pour obtenir une syntaxe correcte')
	elseif args.latitude ~= nil and args.latitude ~= ''
	and args.longitude ~= nil and args.longitude ~= '' then
		tagArgs.latitude = args.latitude
		tagArgs.longitude = args.longitude
	elseif args[1] ~= nil and args[2] ~= nil then
		tagArgs.latitude = args[1]
		tagArgs.longitude = args[2]
	elseif args.commons == nil and args.wikidata == nil
	and args.formes == nil and args.query == nil and args.externes == nil then --The only exceptions allowed to put latitude and longitude away are when using an external map stored on commons, coord from wikidata, formes, query or externes
		error('Les paramètres de latitude et/ou de longitude sont absent')
	end
	
	if tagArgs.latitude ~= nil and tagArgs.longitude ~= nil then
		if tonumber(tagArgs.latitude) then
			tagArgs.latitude = tonumber(tagArgs.latitude)
		else
			tagArgs.latitude = coord._dms2dec(coord._parsedmsstring(tagArgs.latitude))
		end
		if tonumber(tagArgs.longitude) then
			tagArgs.longitude = tonumber(tagArgs.longitude)
		else
			tagArgs.longitude = coord._dms2dec(coord._parsedmsstring(tagArgs.longitude))
		end
	end

	if args.frameless then
		tagArgs.frameless = ''
	end
	
	if args.lang ~= nil then
		tagArgs.lang = args.lang
	end
	
	-- Manage the basics GeoJSON params
	local geojson = {}
	
	if args.commons ~= nil then
		geojson[#geojson+1] = {
			type = "ExternalData",
			service = "page",
			title = args.commons,
		}
	end
	
	if args.marqueur ~= nil and args.marqueur ~= '' then
		geojson[#geojson+1] = {
			type = "Feature",
			geometry = {
				type = "Point",
				coordinates = {
					tagArgs.longitude, 
					tagArgs.latitude
				}
			},
			properties = {
				['marker-color'] = (args.color == nil or args.color == '') and '#555555' or args.color,
	 			['marker-size'] = (args.size == nil or args.size == '') and 'medium' or args.size,
				['marker-symbol'] = args.symbol == nil and '' or args.symbol,
				['title'] = args.title == nil and '' or args.title,
				['description'] = args.description == nil and '' or args.description,
			}
		}
	end
	
	if args.osm ~= nil and args.osm ~= '' then
		local qid
		if args.osm == 'oui' then
			qid = mw.wikibase.getEntityIdForCurrentPage()
			if qid == nil then
				qid = "Q1"
			end
		else
			qid = args.osm
		end
		
		local service = "geoshape"
		if args.contour ~= nil then
			service = "geoline"
		end
		
		geojson[#geojson+1] = {
			type = "ExternalData",
			service = service,
			ids = qid,
			properties = {
				['title'] = args.title == nil and '' or args.title,
				['description'] = args.description == nil and '' or args.description,
				['stroke'] = args.outline_color == nil and '#555555' or args.outline_color,
				['stroke-width'] = args.outline_size == nil and 2 or tonumber(args.outline_size),
			}
		}
	end
	
	local qid = args.wikidata
	if qid and not mw.wikibase.isValidEntityId( qid ) then
		qid = mw.wikibase.getEntityIdForCurrentPage()
	end
	if qid and mw.wikibase.isValidEntityId( qid ) then
		local entity = mw.wikibase.getEntity( qid )
		local value = entity:formatPropertyValues( 'P625', { mw.wikibase.entity.claimRanks.RANK_NORMAL, mw.wikibase.entity.claimRanks.RANK_PREFERRED, mw.wikibase.entity.claimRanks.RANK_TRUTH } ).value
		if value == '' then
			error('La propriété P625 "coordonnées géographiques" n\'est pas renseigné sur Wikidata')
		end
		latlng = mw.text.split( mw.text.decode(value), ", ", true )
		geojson[#geojson+1] = {
			type = "Feature",
			geometry = {
				type = "Point",
				coordinates = {
					coord._dms2dec(coord._parsedmsstring(latlng[2])), 
					coord._dms2dec(coord._parsedmsstring(latlng[1]))
				}
			},
			properties = {
				title = args.title == nil and '' or args.title,
				description = args.description == nil and '' or args.description,
			}
		}
	end
	
	if args.query ~= nil then
		local service = "geoshape"
		if args.contour ~= nil then
			service = "geoline"
		end
		
		geojson[#geojson+1] = {
			type = "ExternalData",
			service = service,
			query = args.query,
			properties = {
				title = args.title == nil and '' or args.title,
				description = args.description == nil and '' or args.description,
			}
		}
	end
	
	--Manage external GeoJSON datas included through models
	if args.formes ~= nil then
		geojson[#geojson+1] = {
			type = "FeatureCollection",
			features = decodeJsonList(args.formes)
		}
	end
	
	if args.externes ~= nil and args.externes ~= '' then
		local externes = decodeJsonList(args.externes)
		for k, externe in pairs(externes) do
			geojson[#geojson+1] = externe
		end
	end
	
	return frame:extensionTag(tagname, mw.text.jsonEncode(geojson), tagArgs)
end

return p