Module:Mapframe: Difference between revisions
Jump to navigation
Jump to search
>Fish and karate m (Protected "Module:Mapframe": Highly visible template ([Edit=Require template editor access] (indefinite) [Move=Require template editor access] (indefinite))) |
>Evad37 (Update from sandbox: better handing for parameter aliases) |
||
Line 6: | Line 6: | ||
-- Template parameter names (unnumbered versions only) | -- Template parameter names (unnumbered versions only) | ||
-- Specify each as either a single string, or a table of strings (aliases) | |||
-- Aliases are checked left-to-right, i.e. `{ "one", "two" }` is equivalent to using `{{{one| {{{two|}}} }}}` in a template | |||
L10n.para = { | L10n.para = { | ||
display = "display", | display = "display", | ||
type = "type", | type = "type", | ||
id = "id", | id = { "id", "ids" }, | ||
from = "from", | from = "from", | ||
raw = "raw", | raw = "raw", | ||
title = "title", | title = "title", | ||
description = "description", | description = "description", | ||
strokeColor = "stroke-color", | strokeColor = { "stroke-color", "stroke-colour" }, | ||
strokeWidth = "stroke-width", | strokeWidth = "stroke-width", | ||
coord = "coord", | coord = "coord", | ||
marker = "marker", | marker = "marker", | ||
markerColor = "marker-color", | markerColor = { "marker-color", "marker-colour" }, | ||
text = "text", | text = "text", | ||
icon = "icon", | icon = "icon", | ||
Line 29: | Line 28: | ||
frameWidth = "frame-width", | frameWidth = "frame-width", | ||
frameHeight = "frame-height", | frameHeight = "frame-height", | ||
frameLatitude = { "frame-lat", "frame-latitude" }, | |||
frameLongitude = { "frame-long", "frame-longitude" }, | |||
frameAlign = "frame-align" | frameAlign = "frame-align" | ||
} | } | ||
Line 105: | Line 102: | ||
-- #### End of L10n settings #### | -- #### End of L10n settings #### | ||
function getParameterValue(args, param_id, suffix) | |||
suffix = suffix or '' | |||
if type( L10n.para[param_id] ) ~= 'table' then | |||
return args[L10n.para[param_id]..suffix] | |||
end | |||
for _i, paramAlias in ipairs(L10n.para[param_id]) do | |||
if args[paramAlias..suffix] then | |||
return args[paramAlias..suffix] | |||
end | |||
end | |||
return nil | |||
end | |||
function setCleanArgs(argsTable) | function setCleanArgs(argsTable) | ||
Line 132: | Line 143: | ||
function makeContent(args) | function makeContent(args) | ||
if args | if getParameterValue(args, 'raw') then | ||
return args | return getParameterValue(args, 'raw') | ||
end | end | ||
local content = {}; | local content = {}; | ||
local contentIndex = ''; | local contentIndex = ''; | ||
local nextTypeOrFromExists = getParameterValue(args, 'type') or getParameterValue(args, 'from') | |||
while nextTypeOrFromExists do | |||
local contentArgs = {} | local contentArgs = {} | ||
for k, v in pairs(args) do | for k, v in pairs(args) do | ||
Line 149: | Line 161: | ||
content[contentIndex] = makeContentJson(contentArgs) | content[contentIndex] = makeContentJson(contentArgs) | ||
contentIndex = contentIndex + 1 | contentIndex = contentIndex + 1 | ||
nextTypeOrFromExists = getParameterValue(args, 'type', contentIndex) or getParameterValue(args, 'from', contentIndex) | |||
end | end | ||
Line 192: | Line 205: | ||
local coords, lat, long | local coords, lat, long | ||
local frame = mw.getCurrentFrame() | local frame = mw.getCurrentFrame() | ||
if args | if getParameterValue(args, 'coord') then | ||
coords = frame:preprocess(args | coords = frame:preprocess( getParameterValue(args, 'coord') ) | ||
lat, long = parseCoords(coords) | lat, long = parseCoords(coords) | ||
else | else | ||
lat, long = wikidataCoords(args | lat, long = wikidataCoords(getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) | ||
end | end | ||
if plainOutput then | if plainOutput then | ||
Line 204: | Line 217: | ||
end | end | ||
function makeContentJson( | function makeContentJson(contentArgs) | ||
local data = {} | local data = {} | ||
if | if getParameterValue(contentArgs, 'type') == L10n.str.point then | ||
data.type = "Feature" | data.type = "Feature" | ||
data.geometry = { | data.geometry = { | ||
type = "Point", | type = "Point", | ||
coordinates = makeCoords( | coordinates = makeCoords(contentArgs) | ||
} | } | ||
data.properties = { | data.properties = { | ||
title = | title = getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle(), | ||
["marker-symbol"] = | ["marker-symbol"] = getParameterValue(contentArgs, 'marker') or L10n.defaults.marker, | ||
["marker-color"] = | ["marker-color"] = getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor | ||
} | } | ||
else | else | ||
data.type = "ExternalData" | data.type = "ExternalData" | ||
if | if getParameterValue(contentArgs, 'type') == L10n.str.data or getParameterValue(contentArgs, 'from') then | ||
data.service = "page" | data.service = "page" | ||
elseif | elseif getParameterValue(contentArgs, 'type') == L10n.str.line then | ||
data.service = "geoline" | data.service = "geoline" | ||
elseif | elseif getParameterValue(contentArgs, 'type') == L10n.str.shape then | ||
data.service = "geoshape" | data.service = "geoshape" | ||
elseif | elseif getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse then | ||
data.service = "geomask" | data.service = "geomask" | ||
end | end | ||
if | if getParameterValue(contentArgs, 'id') or (not (getParameterValue(contentArgs, 'from')) and mw.wikibase.getEntityIdForCurrentPage()) then | ||
data.ids = | data.ids = getParameterValue(contentArgs, 'id') or mw.wikibase.getEntityIdForCurrentPage() | ||
else | else | ||
data.title = | data.title = getParameterValue(contentArgs, 'from') | ||
end | end | ||
data.properties = { | data.properties = { | ||
stroke = | stroke = getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor, | ||
["stroke-width"] = tonumber( | ["stroke-width"] = tonumber(getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth | ||
} | } | ||
end | end | ||
data.properties.title = | data.properties.title = getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():preprocess('{{PAGENAME}}') | ||
if | if getParameterValue(contentArgs, 'description') then | ||
data.properties.description = | data.properties.description = getParameterValue(contentArgs, 'description') | ||
end | end | ||
Line 253: | Line 266: | ||
function makeTagAttribs(args, isTitle) | function makeTagAttribs(args, isTitle) | ||
local attribs = {} | local attribs = {} | ||
if args | if getParameterValue(args, 'zoom') then | ||
attribs.zoom = args | attribs.zoom = getParameterValue(args, 'zoom') | ||
end | end | ||
if isDeclined(args | if isDeclined(getParameterValue(args, 'icon')) then | ||
attribs.class = "no-icon" | attribs.class = "no-icon" | ||
end | end | ||
if args | if getParameterValue(args, '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 | if isAffirmed(getParameterValue(args, 'frame')) and not(isTitle) then | ||
attribs.width = args | attribs.width = getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidth | ||
attribs.height = args | attribs.height = getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeight | ||
if args | if getParameterValue(args, 'frameLatitude') then | ||
attribs.latitude = args | attribs.latitude = getParameterValue(args, 'frameLatitude') | ||
end | end | ||
if args | if getParameterValue(args, 'frameLongitude') then | ||
attribs.longitude = args | attribs.longitude = getParameterValue(args, 'frameLongitude') | ||
end | end | ||
if not attribs.latitude and not attribs.longitude then | if not attribs.latitude and not attribs.longitude then | ||
local success, lat, long = pcall(wikidataCoords, args | local success, lat, long = pcall(wikidataCoords, getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) | ||
if success then | if success then | ||
attribs.latitude = tostring(lat) | attribs.latitude = tostring(lat) | ||
Line 280: | Line 293: | ||
end | end | ||
end | end | ||
if args | if getParameterValue(args, 'frameAlign') then | ||
attribs.align = args | attribs.align = getParameterValue(args, 'frameAlign') | ||
end | end | ||
if isAffirmed(args | if isAffirmed(getParameterValue(args, 'plain')) then | ||
attribs.frameless = "1" | attribs.frameless = "1" | ||
else | else | ||
attribs.text = args | attribs.text = getParameterValue(args, 'text') or L10n.defaults.text | ||
end | end | ||
else | else | ||
attribs.text = args | attribs.text = getParameterValue(args, 'text') or L10n.defaults.text | ||
end | end | ||
return attribs | return attribs | ||
Line 305: | Line 318: | ||
function makeInlineOutput(args, tagContent) | function makeInlineOutput(args, tagContent) | ||
local tagName = 'maplink' | local tagName = 'maplink' | ||
if args | if getParameterValue(args, 'frame') then | ||
tagName = 'mapframe' | tagName = 'mapframe' | ||
end | end | ||
Line 327: | Line 340: | ||
local tagContent = makeContent(args) | local tagContent = makeContent(args) | ||
local display = mw.text.split(args | local display = mw.text.split(getParameterValue(args, 'display') or L10n.defaults.display, '%s*' .. L10n.str.dsep .. '%s*') | ||
local displayInTitle = display[1] == L10n.str.title or display[2] == L10n.str.title | local displayInTitle = display[1] == L10n.str.title or display[2] == L10n.str.title | ||
local displayInline = display[1] == L10n.str.inline or display[2] == L10n.str.inline | local displayInline = display[1] == L10n.str.inline or display[2] == L10n.str.inline |
Revision as of 04:43, 27 May 2018
Documentation for this module may be created at Module:Mapframe/doc
-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe -- ##### Localisation (L10n) settings ##### -- Replace values in quotes ("") with localised values local L10n = {} -- Template parameter names (unnumbered versions only) -- Specify each as either a single string, or a table of strings (aliases) -- Aliases are checked left-to-right, i.e. `{ "one", "two" }` is equivalent to using `{{{one| {{{two|}}} }}}` in a template L10n.para = { display = "display", type = "type", id = { "id", "ids" }, from = "from", raw = "raw", title = "title", description = "description", strokeColor = { "stroke-color", "stroke-colour" }, strokeWidth = "stroke-width", coord = "coord", marker = "marker", markerColor = { "marker-color", "marker-colour" }, text = "text", icon = "icon", zoom = "zoom", frame = "frame", plain = "plain", frameWidth = "frame-width", frameHeight = "frame-height", frameLatitude = { "frame-lat", "frame-latitude" }, frameLongitude = { "frame-long", "frame-longitude" }, frameAlign = "frame-align" } -- Names of other templates this module depends on L10n.template = { Coord = "Coord" } -- Error messages L10n.error = { badDisplayPara = "Invalid display parameter", noCoords = "Coordinates must be specified on Wikidata or in |" .. L10n.para.coord .. "=", wikidataCoords = "Coordinates not found on Wikidata" } -- 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", markerColor = "5E74F3", strokeColor = "#ff0000", strokeWidth = 6 } -- #### End of L10n settings #### function getParameterValue(args, param_id, suffix) suffix = suffix or '' if type( L10n.para[param_id] ) ~= 'table' then return args[L10n.para[param_id]..suffix] end for _i, paramAlias in ipairs(L10n.para[param_id]) do if args[paramAlias..suffix] then return args[paramAlias..suffix] end end return nil end 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 getParameterValue(args, 'raw') then return getParameterValue(args, 'raw') end local content = {}; local contentIndex = ''; local nextTypeOrFromExists = getParameterValue(args, 'type') or getParameterValue(args, 'from') while nextTypeOrFromExists 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 nextTypeOrFromExists = getParameterValue(args, 'type', contentIndex) or getParameterValue(args, 'from', contentIndex) 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 ''), '_') local lat, long if parts[2] == 'N' then lat = parts[1] else lat = '-'..parts[1] end if parts[4] == 'E' then long = parts[3] else long = '-'..parts[3] end return tonumber(lat), tonumber(long) end function wikidataCoords(item_id) if not(mw.wikibase.isValidEntityId(item_id)) or not(mw.wikibase.entityExists(item_id)) then error(L10n.error.noCoords, 0) end local coordStatements = mw.wikibase.getBestStatements(item_id, 'P625') if not coordStatements or #coordStatements == 0 then error(L10n.error.wikidataCoords, 0) end local wdCoords = coordStatements[1]['mainsnak']['datavalue']['value'] return tonumber(wdCoords['latitude']), tonumber(wdCoords['longitude']) end function makeCoords(args, plainOutput) local coords, lat, long local frame = mw.getCurrentFrame() if getParameterValue(args, 'coord') then coords = frame:preprocess( getParameterValue(args, 'coord') ) lat, long = parseCoords(coords) else lat, long = wikidataCoords(getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) end if plainOutput then return lat, long end return {[0] = long, [1] = lat} end function makeContentJson(contentArgs) local data = {} if getParameterValue(contentArgs, 'type') == L10n.str.point then data.type = "Feature" data.geometry = { type = "Point", coordinates = makeCoords(contentArgs) } data.properties = { title = getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle(), ["marker-symbol"] = getParameterValue(contentArgs, 'marker') or L10n.defaults.marker, ["marker-color"] = getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor } else data.type = "ExternalData" if getParameterValue(contentArgs, 'type') == L10n.str.data or getParameterValue(contentArgs, 'from') then data.service = "page" elseif getParameterValue(contentArgs, 'type') == L10n.str.line then data.service = "geoline" elseif getParameterValue(contentArgs, 'type') == L10n.str.shape then data.service = "geoshape" elseif getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse then data.service = "geomask" end if getParameterValue(contentArgs, 'id') or (not (getParameterValue(contentArgs, 'from')) and mw.wikibase.getEntityIdForCurrentPage()) then data.ids = getParameterValue(contentArgs, 'id') or mw.wikibase.getEntityIdForCurrentPage() else data.title = getParameterValue(contentArgs, 'from') end data.properties = { stroke = getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor, ["stroke-width"] = tonumber(getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth } end data.properties.title = getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():preprocess('{{PAGENAME}}') if getParameterValue(contentArgs, 'description') then data.properties.description = getParameterValue(contentArgs, 'description') end return mw.text.jsonEncode(data) end function makeTagAttribs(args, isTitle) local attribs = {} if getParameterValue(args, 'zoom') then attribs.zoom = getParameterValue(args, 'zoom') end if isDeclined(getParameterValue(args, 'icon')) then attribs.class = "no-icon" end if getParameterValue(args, 'type') == L10n.str.point then local lat, long = makeCoords(args, 'plainOutput') attribs.latitude = tostring(lat) attribs.longitude = tostring(long) end if isAffirmed(getParameterValue(args, 'frame')) and not(isTitle) then attribs.width = getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidth attribs.height = getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeight if getParameterValue(args, 'frameLatitude') then attribs.latitude = getParameterValue(args, 'frameLatitude') end if getParameterValue(args, 'frameLongitude') then attribs.longitude = getParameterValue(args, 'frameLongitude') end if not attribs.latitude and not attribs.longitude then local success, lat, long = pcall(wikidataCoords, getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) if success then attribs.latitude = tostring(lat) attribs.longitude = tostring(long) end end if getParameterValue(args, 'frameAlign') then attribs.align = getParameterValue(args, 'frameAlign') end if isAffirmed(getParameterValue(args, 'plain')) then attribs.frameless = "1" else attribs.text = getParameterValue(args, 'text') or L10n.defaults.text end else attribs.text = getParameterValue(args, '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 getParameterValue(args, 'frame') then tagName = 'mapframe' end return mw.text.tag(tagName, makeTagAttribs(args), tagContent) end local p = {} -- Entry point for templates function p.main(frame) local parent = frame.getParent(frame) local output = p._main(parent.args) return frame:preprocess(output) end -- Entry point for modules function p._main(_args) local args = setCleanArgs(_args) local tagContent = makeContent(args) local display = mw.text.split(getParameterValue(args, 'display') or L10n.defaults.display, '%s*' .. L10n.str.dsep .. '%s*') local displayInTitle = display[1] == L10n.str.title or display[2] == L10n.str.title local displayInline = display[1] == L10n.str.inline or display[2] == L10n.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 output end return p