Module:Mapframe: Difference between revisions

From Random Island Wiki
Jump to navigation Jump to search
>Evad37
(cleanup)
>Evad37
(Tanslations and other localisation setting)
Line 1: Line 1:
local defaults = {
-- ##### Localisation (L10n) settings #####
display = 'inline',
-- Replace values in quotes ("") with localised values
text = 'Map',
 
["frame-width"] = '300',
local L10n = {}
["frame-height"] = '200'
 
-- Template parameter names (unnumbered versions only)
L10n.para = {
display = "display",
type = "type",
id              = "id",
ids            = "ids",
from = "from",
raw = "raw",
title = "title",
description = "description",
strokeColor    = "stroke-color",
strokeColour    = "stroke-colour",
strokeWidth = "stroke-width",
coord = "coord",
marker = "marker",
markerColor = "marker-color",
markerColour = "marker-colour",
text = "text",
icon = "icon",
zoom = "zoom",
frame = "frame",
plain = "plain",
frameWidth = "frame-width",
frameHeight = "frame-height",
frameLat = "frame-lat",
frameLatitude = "frame-latitude",
frameLong = "frame-long",
frameLongitude = "frame-longitude"
}
 
-- Names of other templates this module depends on
L10n.template = {
Coord = "Coord",
WikidataCoord = "WikidataCoord"
}
}
-- Error messages
L10n.error = {
badDisplayPara = "Invalid display parameter"
}
-- Other strings
L10n.str = {
-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline)
inline = "inline",
title = "title",
dsep = ",", -- separator between inline and title (comma in the example above)
-- valid values for type paramter
line = "line", -- geoline feature (e.g. a road)
shape = "shape", -- geoshape feature (e.g. a state or province)
shapeInverse = "shape-inverse", -- geomask feature (the inverse of a geoshape)
data = "data", -- geoJSON data page on Commons
point = "point", -- single point feature (coordinates)
-- valid values for icon, frame, and plain parameters
affirmedWords = ' '..table.concat({
"add",
"added",
"affirm",
"affirmed",
"include",
"included",
"on",
"true",
"yes",
"y"
}, ' ')..' ',
declinedWords = ' '..table.concat({
"decline",
"declined",
"exclude",
"excluded",
"false",
"none",
"not",
"no",
"n",
"off",
"omit",
"omitted",
"remove",
"removed"
}, ' ')..' '
}
-- Default values for parameters
L10n.defaults = {
display = L10n.str.inline,
text = "Map",
frameWidth = "300",
frameHeight = "200",
marker = "marker", -- Do not translate. For valid alternate values, see https://www.mediawiki.org/wiki/Maps/Icons
markerColor = "5E74F3",
strokeColor = "#ff0000",
strokeWidth = 6
}
-- #### End of L10n settings ####


function setCleanArgs(argsTable)
function setCleanArgs(argsTable)
Line 23: Line 121:
function isAffirmed(val)
function isAffirmed(val)
if not(val) then return false end
if not(val) then return false end
local affirmedWords = ' add added affirm affirmed include included on true yes y '
return string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or false
return string.find(affirmedWords, ' '..val..' ', 1, true ) and true or false
end
end


function isDeclined(val)
function isDeclined(val)
if not(val) then return false end
if not(val) then return false end
local declinedWords = ' decline declined exclude excluded false none not no n off omit omitted remove removed '
return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false
return string.find(declinedWords , ' '..val..' ', 1, true ) and true or false
end
end


function makeContent(args)
function makeContent(args)
if args.raw then
if args[L10n.para.raw] then
return args.raw
return args[L10n.para.raw]
end
end


local content = {};
local content = {};
local contentIndex = '';
local contentIndex = '';
while args['type'..contentIndex] or args['from'..contentIndex] do
while args[L10n.para.type .. contentIndex] or args[L10n.para.from .. contentIndex] do
local contentArgs = {}
local contentArgs = {}
for k, v in pairs(args) do
for k, v in pairs(args) do
Line 75: Line 171:
local coords
local coords
local frame = mw.getCurrentFrame()
local frame = mw.getCurrentFrame()
if args.coord then
if args[L10n.para.coord] then
coords = frame:preprocess(args.coord)
coords = frame:preprocess(args[L10n.para.coord])
else
else
coords = frame:preprocess('{{WikidataCoord|display=|'..(args.id or args.ids or mw.wikibase.getEntityIdForCurrentPage())..'}}')
coords = frame:preprocess('{{' .. L10n.template.WikidataCoord .. '|display=|' .. (args[L10n.para.id] or args[L10n.para.ids] or mw.wikibase.getEntityIdForCurrentPage()) .. '}}')
end
end
local lat, long = parseCoords(coords)
local lat, long = parseCoords(coords)
Line 90: Line 186:
local data = {}
local data = {}


if args.type == 'point' then
if args[L10n.para.type] == L10n.str.point then
data.type = "Feature"
data.type = "Feature"
data.geometry = {
data.geometry = {
Line 97: Line 193:
}
}
data.properties = {
data.properties = {
title = args.title or mw.getCurrentFrame():getParent():getTitle(),
title = args[L10n.para.title] or mw.getCurrentFrame():getParent():getTitle(),
["marker-symbol"] = args.marker or "marker",
["marker-symbol"] = args[L10n.para.marker] or L10n.defaults.marker,
["marker-color"] = "5E74F3"
["marker-color"] = args[L10n.para.markerColor] or args[L10n.para.markerColour] or L10n.defaults.markerColor
}
}
else
else
data.type = "ExternalData"
data.type = "ExternalData"


if args.type == "data" or args.from then
if args[L10n.para.type] == L10n.str.data or args[L10n.para.from] then
data.service = "page"
data.service = "page"
elseif args.type == "line" then
elseif args[L10n.para.type] == L10n.str.line then
data.service = "geoline"
data.service = "geoline"
elseif args.type == "shape" then
elseif args[L10n.para.type] == L10n.str.shape then
data.service = "geoshape"
data.service = "geoshape"
elseif args.type == "shape-inverse" then
elseif argsargs[L10n.para.type] == L10n.str.shape-inverse then
data.service = "geomask"
data.service = "geomask"
end
end


if args.id or args.ids or (not (args.from) and mw.wikibase.getEntityIdForCurrentPage()) then
if args[L10n.para.id] or args[L10n.para.ids] or (not (args[L10n.para.from]) and mw.wikibase.getEntityIdForCurrentPage()) then
data.ids = args.id or args.ids or mw.wikibase.getEntityIdForCurrentPage()
data.ids = args[L10n.para.id] or args[L10n.para.ids] or mw.wikibase.getEntityIdForCurrentPage()
else  
else  
data.title = args.from
data.title = args[L10n.para.from]
end
end


data.properties = {
data.properties = {
stroke = args["stroke-color"] or args["stroke-colour"] or "#ff0000",
stroke = args[L10n.para.strokeColor] or args[L10n.para.strokeColour] or L10.defaults.strokeColor,
["stroke-width"] = tonumber(args["stroke-width"]) or 6
["stroke-width"] = tonumber(args[L10n.para.strokeWidth]) or L10n.defaults.strokeWidth
}
}
end
end


data.properties.title = args.title or mw.getCurrentFrame():getParent():getTitle()
data.properties.title = args[L10n.para.title] or mw.getCurrentFrame():getParent():getTitle()
if args.description then
if args[L10n.para.description] then
data.properties.description = args.description
data.properties.description = args[L10n.para.description]
end
end


Line 136: Line 232:
function makeTagAttribs(args, isTitle)
function makeTagAttribs(args, isTitle)
local attribs = {}
local attribs = {}
if args.zoom then
if args[L10n.para.zoom] then
attribs.zoom = args.zoom
attribs.zoom = args[L10n.para.zoom]
end
end
if isDeclined(args.icon) then
if isDeclined(args[L10n.para.icon]) then
attribs.class = "no-icon"
attribs.class = "no-icon"
end
end
if args.type == 'point' then
if args[L10n.para.type] == L10n.str.point then
local lat, long = makeCoords(args, 'plainOutput')
local lat, long = makeCoords(args, 'plainOutput')
attribs.latitude = tostring(lat)
attribs.latitude = tostring(lat)
attribs.longitude = tostring(long)
attribs.longitude = tostring(long)
end
end
if isAffirmed(args.frame) and not(isTitle) then
if isAffirmed(args[L10n.para.frame]) and not(isTitle) then
attribs.width = args["frame-width"] or defaults["frame-width"]
attribs.width = args[L10n.para.frameWidth] or L10n.defaults.frameWidth
attribs.height = args["frame-height"] or defaults["frame-height"]
attribs.height = args[L10n.para.frameHeight] or L10n.defaults.frameHeight
if args["frame-lat"] or args["frame-latitude"] then
if args[L10n.para.frameLat] or args[L10n.para.frameLatitude] then
attribs.latitude = args["frame-lat"] or args["frame-latitude"]
attribs.latitude = args[L10n.para.frameLat] or args[L10n.para.frameLatitude]
end
end
if args["frame-long"] or args["frame-longitude"] then
if args[L10n.para.frameLong] or args[L10n.para.frameLongitude] then
attribs.longitude = args["frame-long"] or args["frame-longitude"]
attribs.longitude = args[L10n.para.frameLong] or args[L10n.para.frameLongitude]
end
end
if isAffirmed(args.plain) then
if isAffirmed(args[L10n.para.plain]) then
attribs.frameless = "1"
attribs.frameless = "1"
else
else
attribs.text = args.text or defaults.text
attribs.text = args[L10n.para.text] or L10n.defaults.text
end
end
else
else
attribs.text = args.text or defaults.text
attribs.text = args[L10n.para.text] or L10n.defaults.text
end
end
return attribs
return attribs
Line 178: Line 274:
function makeInlineOutput(args, tagContent)
function makeInlineOutput(args, tagContent)
local tagName = 'maplink'
local tagName = 'maplink'
if args.frame then
if args[L10n.para.frame] then
tagName = 'mapframe'
tagName = 'mapframe'
end
end
Line 193: Line 289:
local tagContent = makeContent(args)
local tagContent = makeContent(args)


local display = mw.text.split(args.display or defaults.display, '%s*,%s*')
local display = mw.text.split(args[L10n.para.display] or L10n.defaults.display, '%s*' .. L10.str.dsep .. '%s*')
local displayInTitle = display[1] == 'title' or display[2] == 'title'
local displayInTitle = display[1] == L10.str.title or display[2] == L10.str.title
local displayInline = display[1] == 'inline' or display[2] == 'inline'
local displayInline = display[1] == L10.str.inline or display[2] == L10.str.inline


local output
local output
Line 205: Line 301:
output = makeInlineOutput(args, tagContent)
output = makeInlineOutput(args, tagContent)
else
else
error( 'Invalid display parameter')
error(L10n.error.badDisplayPara)
end
end



Revision as of 01:07, 3 May 2018

Documentation for this module may be created at Module:Mapframe/doc

-- ##### Localisation (L10n) settings #####
-- Replace values in quotes ("") with localised values

local L10n = {}

-- Template parameter names (unnumbered versions only)
L10n.para = {
	display		= "display",
	type		= "type",
	id              = "id",
	ids             = "ids",
	from		= "from",
	raw		= "raw",
	title		= "title",
	description	= "description",
	strokeColor     = "stroke-color",
	strokeColour    = "stroke-colour",
	strokeWidth	= "stroke-width",
	coord		= "coord",
	marker		= "marker",
	markerColor	= "marker-color",
	markerColour	= "marker-colour",
	text		= "text",
	icon		= "icon",
	zoom		= "zoom",
	frame		= "frame",
	plain		= "plain",
	frameWidth	= "frame-width",
	frameHeight	= "frame-height",
	frameLat	= "frame-lat",
	frameLatitude	= "frame-latitude",
	frameLong	= "frame-long",
	frameLongitude	= "frame-longitude"
}

-- Names of other templates this module depends on
L10n.template = {
	Coord		= "Coord",
	WikidataCoord	= "WikidataCoord"
}

-- Error messages
L10n.error = {
	badDisplayPara	= "Invalid display parameter"
}

-- Other strings
L10n.str = {
	-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline)
	inline		= "inline",			
	title		= "title",	
	dsep		= ",",			-- separator between inline and title (comma in the example above)

	-- valid values for type paramter
	line		= "line",		-- geoline feature (e.g. a road)
	shape		= "shape",		-- geoshape feature (e.g. a state or province)
	shapeInverse	= "shape-inverse",	-- geomask feature (the inverse of a geoshape)
	data		= "data",		-- geoJSON data page on Commons
	point		= "point",		-- single point feature (coordinates)

	-- valid values for icon, frame, and plain parameters
	affirmedWords = ' '..table.concat({
		"add",
		"added",
		"affirm",
		"affirmed",
		"include",
		"included",
		"on",
		"true",
		"yes",
		"y"
	}, ' ')..' ',
	declinedWords = ' '..table.concat({
		"decline",
		"declined",
		"exclude",
		"excluded",
		"false",
		"none",
		"not",
		"no",
		"n",
		"off",
		"omit",
		"omitted",
		"remove",
		"removed"
	}, ' ')..' '
}

-- Default values for parameters
L10n.defaults = {
	display		= L10n.str.inline,
	text		= "Map",
	frameWidth	= "300",
	frameHeight	= "200",
	marker		= "marker",		-- Do not translate. For valid alternate values, see https://www.mediawiki.org/wiki/Maps/Icons
	markerColor	= "5E74F3",
	strokeColor	= "#ff0000",
	strokeWidth	= 6
}

-- #### End of L10n settings ####

function setCleanArgs(argsTable)
	local cleanArgs = {}
	for key, val in pairs(argsTable) do
		if type(val) == 'string' then
			val = val:match('^%s*(.-)%s*$')
			if val ~= '' then
				cleanArgs[key] = val
			end
		else
			cleanArgs[key] = val
		end
	end
	return cleanArgs
end

function isAffirmed(val)
	if not(val) then return false end
	return string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or false
end

function isDeclined(val)
	if not(val) then return false end
	return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false
end

function makeContent(args)
	if args[L10n.para.raw] then
		return args[L10n.para.raw]
	end

	local content = {};
	local contentIndex = '';
	while args[L10n.para.type .. contentIndex] or args[L10n.para.from .. contentIndex] do
		local contentArgs = {}
		for k, v in pairs(args) do
			if string.match(k, '.*'..contentIndex) then
				contentArgs[string.gsub(k, contentIndex, '')] = v
			end
		end

		if contentIndex == '' then contentIndex = 1 end
		content[contentIndex] = makeContentJson(contentArgs)
		contentIndex = contentIndex + 1
	end
	
	--Single item, no array needed
	if #content==1 then return content[1] end

	--Multiple items get placed in a FeatureCollection
	local contentArray = '[\n' .. table.concat( content, ',\n') .. '\n]'
	return contentArray
end

function parseCoords(coords)
	local parts = mw.text.split((mw.ustring.match(coords,'[%.%d]+°[NS] [%.%d]+°[EW]') or ''), ' ')

	latParts = mw.text.split(parts[1], '°')
	longParts = mw.text.split(parts[2], '°')

	if latParts[2] == 'S' then latParts[1] = '-'..latParts[1] end
	if longParts[2] == 'W' then longParts[1] = '-'..longParts[1] end
	return tonumber(latParts[1]), tonumber(longParts[1])
end

function makeCoords(args, plainOutput) 
	local coords
	local frame = mw.getCurrentFrame()
	if args[L10n.para.coord] then
		coords = frame:preprocess(args[L10n.para.coord])
	else
		coords = frame:preprocess('{{' .. L10n.template.WikidataCoord .. '|display=|' .. (args[L10n.para.id] or args[L10n.para.ids] or mw.wikibase.getEntityIdForCurrentPage()) .. '}}')
	end
	local lat, long = parseCoords(coords)
	if plainOutput then
		return lat, long
	end
	return {[0] = long, [1] = lat}
end

function makeContentJson(args)
	local data = {}

	if args[L10n.para.type] == L10n.str.point then
		data.type = "Feature"
		data.geometry = {
			type = "Point",
			coordinates = makeCoords(args)
		}
		data.properties = {
			title = args[L10n.para.title] or mw.getCurrentFrame():getParent():getTitle(),
			["marker-symbol"] = args[L10n.para.marker] or L10n.defaults.marker,
			["marker-color"] = args[L10n.para.markerColor] or args[L10n.para.markerColour] or L10n.defaults.markerColor
		}
	else
		data.type = "ExternalData"

		if args[L10n.para.type] == L10n.str.data or args[L10n.para.from] then
			data.service = "page"
		elseif args[L10n.para.type] == L10n.str.line then
			data.service = "geoline"
		elseif args[L10n.para.type] == L10n.str.shape then
			data.service = "geoshape"
		elseif argsargs[L10n.para.type] == L10n.str.shape-inverse then
			data.service = "geomask"
		end

		if args[L10n.para.id] or args[L10n.para.ids] or (not (args[L10n.para.from]) and mw.wikibase.getEntityIdForCurrentPage()) then
			data.ids = args[L10n.para.id] or args[L10n.para.ids] or mw.wikibase.getEntityIdForCurrentPage()
		else 
			data.title = args[L10n.para.from]
		end

		data.properties = {
			stroke = args[L10n.para.strokeColor] or args[L10n.para.strokeColour] or L10.defaults.strokeColor,
			["stroke-width"] = tonumber(args[L10n.para.strokeWidth]) or L10n.defaults.strokeWidth
		}
	end

	data.properties.title = args[L10n.para.title] or mw.getCurrentFrame():getParent():getTitle()
	if args[L10n.para.description] then
		data.properties.description = args[L10n.para.description]
	end

	return mw.text.jsonEncode(data)
end

function makeTagAttribs(args, isTitle)
	local attribs = {}
	if args[L10n.para.zoom] then
		attribs.zoom = args[L10n.para.zoom]
	end
	if isDeclined(args[L10n.para.icon]) then
		attribs.class = "no-icon"
	end
	if args[L10n.para.type] == L10n.str.point then
		local lat, long = makeCoords(args, 'plainOutput')
		attribs.latitude = tostring(lat)
		attribs.longitude = tostring(long)
	end
	if isAffirmed(args[L10n.para.frame]) and not(isTitle) then
		attribs.width = args[L10n.para.frameWidth] or L10n.defaults.frameWidth
		attribs.height = args[L10n.para.frameHeight] or L10n.defaults.frameHeight
		if args[L10n.para.frameLat] or args[L10n.para.frameLatitude] then
			attribs.latitude = args[L10n.para.frameLat] or args[L10n.para.frameLatitude]
		end
		if args[L10n.para.frameLong] or args[L10n.para.frameLongitude] then
			attribs.longitude = args[L10n.para.frameLong] or args[L10n.para.frameLongitude]
		end
		if isAffirmed(args[L10n.para.plain]) then
			attribs.frameless = "1"
		else
			attribs.text = args[L10n.para.text] or L10n.defaults.text
		end
	else
		attribs.text = args[L10n.para.text] or L10n.defaults.text
	end
	return attribs
end

function makeTitleOutput(args, tagContent)
 	local titleTag = mw.text.tag('maplink', makeTagAttribs(args, true), tagContent)
	local spanAttribs = {
		style = "font-size: small;",
		id = "coordinates"
	}
	return mw.text.tag('span', spanAttribs, titleTag)
end

function makeInlineOutput(args, tagContent)
	local tagName = 'maplink'
	if args[L10n.para.frame] then
		tagName = 'mapframe'
	end

	return mw.text.tag(tagName, makeTagAttribs(args), tagContent)
end

local p = {}

function p.main(frame)
	local parent = frame.getParent(frame)
	local args = setCleanArgs(parent.args)
 
	local tagContent = makeContent(args)

	local display = mw.text.split(args[L10n.para.display] or L10n.defaults.display, '%s*' .. L10.str.dsep .. '%s*')
	local displayInTitle = display[1] ==  L10.str.title or display[2] ==  L10.str.title
	local displayInline = display[1] ==  L10.str.inline or display[2] ==  L10.str.inline

	local output
	if displayInTitle and displayInline then
		output = makeTitleOutput(args, tagContent) .. makeInlineOutput(args, tagContent)
	elseif displayInTitle then
		output = makeTitleOutput(args, tagContent)
	elseif displayInline then
		output = makeInlineOutput(args, tagContent)
	else
		error(L10n.error.badDisplayPara)
	end

	return frame:preprocess(output)
end

return p