Diff: Module:Mapframe
Comparing revision #1 (2023-03-21 11:20:30) with revision #2 (2024-03-04 22:45:19).
| Old | New |
|---|---|
-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe |
-- Note: Originally written on English Wikipedia at https://en.wikipedia.org/wiki/Module:Mapframe |
--[[---------------------------------------------------------------------------- |
--[[---------------------------------------------------------------------------- |
##### Localisation (L10n) settings ##### |
##### Localisation (L10n) settings ##### |
Replace values in quotes ("") with localised values |
Replace values in quotes ("") with localised values |
----------------------------------------------------------------------------]]-- |
----------------------------------------------------------------------------]]-- |
local L10n = {} |
local L10n = {} |
-- Modue dependencies |
-- Modue dependencies |
local transcluder -- local copy of https://www.mediawiki.org/wiki/Module:Transcluder loaded lazily |
local transcluder -- local copy of https://www.mediawiki.org/wiki/Module:Transcluder loaded lazily |
-- "strict" should not be used, at least until all other modules which require this module are not using globals. |
-- "strict" should not be used, at least until all other modules which require this module are not using globals. |
-- 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) |
-- 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 |
-- 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", "ids" }, |
id = { "id", "ids" }, |
from = "from", |
from = "from", |
raw = "raw", |
raw = "raw", |
title = "title", |
title = "title", |
description = "description", |
description = "description", |
strokeColor = { "stroke-color", "stroke-colour" }, |
strokeColor = { "stroke-color", "stroke-colour" }, |
strokeWidth = "stroke-width", |
strokeWidth = "stroke-width", |
strokeOpacity = "stroke-opacity", |
strokeOpacity = "stroke-opacity", |
fill = "fill", |
fill = "fill", |
fillOpacity = "fill-opacity", |
fillOpacity = "fill-opacity", |
coord = "coord", |
coord = "coord", |
marker = "marker", |
marker = "marker", |
markerColor = { "marker-color", "marker-colour" }, |
markerColor = { "marker-color", "marker-colour" }, |
markerSize = "marker-size", |
markerSize = "marker-size", |
radius = { "radius", "radius_m" }, |
radius = { "radius", "radius_m" }, |
radiusKm = "radius_km", |
radiusKm = "radius_km", |
radiusFt = "radius_ft", |
radiusFt = "radius_ft", |
radiusMi = "radius_mi", |
radiusMi = "radius_mi", |
edges = "edges", |
edges = "edges", |
text = "text", |
text = "text", |
icon = "icon", |
icon = "icon", |
zoom = "zoom", |
zoom = "zoom", |
frame = "frame", |
frame = "frame", |
plain = "plain", |
plain = "plain", |
frameWidth = "frame-width", |
frameWidth = "frame-width", |
frameHeight = "frame-height", |
frameHeight = "frame-height", |
frameCoordinates = { "frame-coordinates", "frame-coord" }, |
frameCoordinates = { "frame-coordinates", "frame-coord" }, |
frameLatitude = { "frame-lat", "frame-latitude" }, |
frameLatitude = { "frame-lat", "frame-latitude" }, |
frameLongitude = { "frame-long", "frame-longitude" }, |
frameLongitude = { "frame-long", "frame-longitude" }, |
frameAlign = "frame-align", |
frameAlign = "frame-align", |
switch = "switch", |
switch = "switch", |
overlay = "overlay", |
overlay = "overlay", |
overlayBorder = "overlay-border", |
overlayBorder = "overlay-border", |
overlayHorizontalAlignment = "overlay-horizontal-alignment", |
overlayHorizontalAlignment = "overlay-horizontal-alignment", |
overlayVerticalAlignment = "overlay-vertical-alignment", |
overlayVerticalAlignment = "overlay-vertical-alignment", |
overlayHorizontalOffset = "overlay-horizontal-offset", |
overlayHorizontalOffset = "overlay-horizontal-offset", |
overlayVerticalOffset = "overlay-vertical-offset" |
overlayVerticalOffset = "overlay-vertical-offset" |
} |
} |
-- Names of other templates this module can extract coordinates from |
-- Names of other templates this module can extract coordinates from |
L10n.template = { |
L10n.template = { |
coord = { -- The coord template, as well as templates with output that contains {{coord}} |
coord = { -- The coord template, as well as templates with output that contains {{coord}} |
"Coord", "Coord/sandbox", |
"Coord", "Coord/sandbox", |
"NRHP row", "NRHP row/sandbox", |
"NRHP row", "NRHP row/sandbox", |
"WikidataCoord", "WikidataCoord/sandbox", "Wikidatacoord", "Wikidata coord" |
"WikidataCoord", "WikidataCoord/sandbox", "Wikidatacoord", "Wikidata coord" |
} |
} |
} |
} |
-- Error messages |
-- Error messages |
L10n.error = { |
L10n.error = { |
badDisplayPara = "Invalid display parameter", |
badDisplayPara = "Invalid display parameter", |
noCoords = "Coordinates must be specified on Wikidata or in |" .. ( type(L10n.para.coord)== 'table' and L10n.para.coord[1] or L10n.para.coord ) .. "=", |
noCoords = "Coordinates must be specified on Wikidata or in |" .. ( type(L10n.para.coord)== 'table' and L10n.para.coord[1] or L10n.para.coord ) .. "=", |
wikidataCoords = "Coordinates not found on Wikidata", |
wikidataCoords = "Coordinates not found on Wikidata", |
noCircleCoords = "Circle centre coordinates must be specified, or available via Wikidata", |
noCircleCoords = "Circle centre coordinates must be specified, or available via Wikidata", |
negativeRadius = "Circle radius must be a positive number", |
negativeRadius = "Circle radius must be a positive number", |
noRadius = "Circle radius must be specified", |
noRadius = "Circle radius must be specified", |
negativeEdges = "Circle edges must be a positive number", |
negativeEdges = "Circle edges must be a positive number", |
noSwitchPara = "Found only one switch value in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=", |
noSwitchPara = "Found only one switch value in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=", |
oneSwitchLabel = "Found only one label in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=", |
oneSwitchLabel = "Found only one label in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=", |
noSwitchLists = "At least one parameter must have a SWITCH: list", |
noSwitchLists = "At least one parameter must have a SWITCH: list", |
switchMismatches = "All SWITCH: lists must have the same number of values", |
switchMismatches = "All SWITCH: lists must have the same number of values", |
-- "%s" and "%d" tokens will be replaced with strings and numbers when used |
-- "%s" and "%d" tokens will be replaced with strings and numbers when used |
oneSwitchValue = "Found only one switch value in |%s=", |
oneSwitchValue = "Found only one switch value in |%s=", |
fewerSwitchLabels = "Found %d switch values but only %d labels in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=", |
fewerSwitchLabels = "Found %d switch values but only %d labels in |" .. ( type(L10n.para.switch)== 'table' and L10n.para.switch[1] or L10n.para.switch ) .. "=", |
noNamedCoords = "No named coordinates found in %s" |
noNamedCoords = "No named coordinates found in %s" |
} |
} |
-- Other strings |
-- Other strings |
L10n.str = { |
L10n.str = { |
-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline) |
-- valid values for display parameter, e.g. (|display=inline) or (|display=title) or (|display=inline,title) or (|display=title,inline) |
inline = "inline", |
inline = "inline", |
title = "title", |
title = "title", |
dsep = ",", -- separator between inline and title (comma in the example above) |
dsep = ",", -- separator between inline and title (comma in the example above) |
-- valid values for type paramter |
-- valid values for type paramter |
line = "line", -- geoline feature (e.g. a road) |
line = "line", -- geoline feature (e.g. a road) |
shape = "shape", -- geoshape feature (e.g. a state or province) |
shape = "shape", -- geoshape feature (e.g. a state or province) |
shapeInverse = "shape-inverse", -- geomask feature (the inverse of a geoshape) |
shapeInverse = "shape-inverse", -- geomask feature (the inverse of a geoshape) |
data = "data", -- geoJSON data page on Commons |
data = "data", -- geoJSON data page on Commons |
point = "point", -- single point feature (coordinates) |
point = "point", -- single point feature (coordinates) |
circle = "circle", -- circular area around a point |
circle = "circle", -- circular area around a point |
named = "named", -- all named coordinates in an article or section |
named = "named", -- all named coordinates in an article or section |
-- Keyword to indicate a switch list. Must NOT use the special characters ^$()%.[]*+-? |
-- Keyword to indicate a switch list. Must NOT use the special characters ^$()%.[]*+-? |
switch = "SWITCH", |
switch = "SWITCH", |
-- valid values for icon, frame, and plain parameters |
-- valid values for icon, frame, and plain parameters |
affirmedWords = ' '..table.concat({ |
affirmedWords = ' '..table.concat({ |
"add", |
"add", |
"added", |
"added", |
"affirm", |
"affirm", |
"affirmed", |
"affirmed", |
"include", |
"include", |
"included", |
"included", |
"on", |
"on", |
"true", |
"true", |
"yes", |
"yes", |
"y" |
"y" |
}, ' ')..' ', |
}, ' ')..' ', |
declinedWords = ' '..table.concat({ |
declinedWords = ' '..table.concat({ |
"decline", |
"decline", |
"declined", |
"declined", |
"exclude", |
"exclude", |
"excluded", |
"excluded", |
"false", |
"false", |
"none", |
"none", |
"not", |
"not", |
"no", |
"no", |
"n", |
"n", |
"off", |
"off", |
"omit", |
"omit", |
"omitted", |
"omitted", |
"remove", |
"remove", |
"removed" |
"removed" |
}, ' ')..' ' |
}, ' ')..' ' |
} |
} |
-- Default values for parameters |
-- Default values for parameters |
L10n.defaults = { |
L10n.defaults = { |
display = L10n.str.inline, |
display = L10n.str.inline, |
text = "Map", |
text = "Map", |
frameWidth = "300", |
frameWidth = "300", |
frameHeight = "200", |
frameHeight = "200", |
frameAlign = "right", |
frameAlign = "right", |
markerColor = "5E74F3", |
markerColor = "5E74F3", |
markerSize = nil, |
markerSize = nil, |
strokeColor = "#ff0000", |
strokeColor = "#ff0000", |
strokeWidth = 6, |
strokeWidth = 6, |
edges = 32, -- number of edges used to approximate a circle |
edges = 32, -- number of edges used to approximate a circle |
overlayBorder = "1px solid white", |
overlayBorder = "1px solid white", |
overlayHorizontalAlignment = "right", |
overlayHorizontalAlignment = "right", |
overlayHorizontalOffset = "0", |
overlayHorizontalOffset = "0", |
overlayVerticalAlignment = "bottom", |
overlayVerticalAlignment = "bottom", |
overlayVerticalOffset = "0" |
overlayVerticalOffset = "0" |
} |
} |
-- #### End of L10n settings #### |
-- #### End of L10n settings #### |
--[[---------------------------------------------------------------------------- |
--[[---------------------------------------------------------------------------- |
Utility methods |
Utility methods |
----------------------------------------------------------------------------]]-- |
----------------------------------------------------------------------------]]-- |
local util = {} |
local util = {} |
--[[ |
--[[ |
Looks up a parameter value based on the id (a key from the L10n.para table) and |
Looks up a parameter value based on the id (a key from the L10n.para table) and |
optionally a suffix, for parameters that can be suffixed (e.g. type2 is type |
optionally a suffix, for parameters that can be suffixed (e.g. type2 is type |
with suffix 2). |
with suffix 2). |
@param {table} args key-value pairs of parameter names and their values |
@param {table} args key-value pairs of parameter names and their values |
@param {string} param_id id for parameter name (key from the L10n.para table) |
@param {string} param_id id for parameter name (key from the L10n.para table) |
@param {string} [suffix] suffix for parameter name |
@param {string} [suffix] suffix for parameter name |
@returns {string|nil} parameter value if found, or nil if not found |
@returns {string|nil} parameter value if found, or nil if not found |
]]-- |
]]-- |
function util.getParameterValue(args, param_id, suffix) |
function util.getParameterValue(args, param_id, suffix) |
suffix = suffix or '' |
suffix = suffix or '' |
if type( L10n.para[param_id] ) ~= 'table' then |
if type( L10n.para[param_id] ) ~= 'table' then |
return args[L10n.para[param_id]..suffix] |
return args[L10n.para[param_id]..suffix] |
end |
end |
for _i, paramAlias in ipairs(L10n.para[param_id]) do |
for _i, paramAlias in ipairs(L10n.para[param_id]) do |
if args[paramAlias..suffix] then |
if args[paramAlias..suffix] then |
return args[paramAlias..suffix] |
return args[paramAlias..suffix] |
end |
end |
end |
end |
return nil |
return nil |
end |
end |
--[[ |
--[[ |
Trim whitespace from args, and remove empty args. Also fix control characters. |
Trim whitespace from args, and remove empty args. Also fix control characters. |
@param {table} argsTable |
@param {table} argsTable |
@returns {table} trimmed args table |
@returns {table} trimmed args table |
]]-- |
]]-- |
function util.trimArgs(argsTable) |
function util.trimArgs(argsTable) |
local cleanArgs = {} |
local cleanArgs = {} |
for key, val in pairs(argsTable) do |
for key, val in pairs(argsTable) do |
if type(key) == 'string' and type(val) == 'string' then |
if type(key) == 'string' and type(val) == 'string' then |
val = val:match('^%s*(.-)%s*$') |
val = val:match('^%s*(.-)%s*$') |
if val ~= '' then |
if val ~= '' then |
-- control characters inside json need to be escaped, but stripping them is simpler |
-- control characters inside json need to be escaped, but stripping them is simpler |
-- See also T214984 |
-- See also T214984 |
-- However, *don't* strip control characters from wikitext (text or description parameters) or you'll break strip markers |
-- However, *don't* strip control characters from wikitext (text or description parameters) or you'll break strip markers |
-- Alternatively it might be better to only strip control char from raw parameter content |
-- Alternatively it might be better to only strip control char from raw parameter content |
if util.matchesParam('text', key) or util.matchesParam('description', key, key:gsub('^%D+(%d+)$', '%1') ) then |
if util.matchesParam('text', key) or util.matchesParam('description', key, key:gsub('^%D+(%d+)$', '%1') ) then |
cleanArgs[key] = val |
cleanArgs[key] = val |
else |
else |
cleanArgs[key] = val:gsub('%c',' ') |
cleanArgs[key] = val:gsub('%c',' ') |
end |
end |
end |
end |
else |
else |
cleanArgs[key] = val |
cleanArgs[key] = val |
end |
end |
end |
end |
return cleanArgs |
return cleanArgs |
end |
end |
--[[ |
--[[ |
Check if a parameter name matches an unlocalized parameter key |
Check if a parameter name matches an unlocalized parameter key |
@param {string} key - the unlocalized parameter name to search through |
@param {string} key - the unlocalized parameter name to search through |
@param {string} name - the localized parameter name to check |
@param {string} name - the localized parameter name to check |
@param {string|nil} - an optional suffix to apply to the value(s) from the localization key |
@param {string|nil} - an optional suffix to apply to the value(s) from the localization key |
@returns {boolean} true if the name matches the parameter, false otherwise |
@returns {boolean} true if the name matches the parameter, false otherwise |
]]-- |
]]-- |
function util.matchesParam(key, name, suffix) |
function util.matchesParam(key, name, suffix) |
local param = L10n.para[key] |
local param = L10n.para[key] |
suffix = suffix or '' |
suffix = suffix or '' |
if type(param) == 'table' then |
if type(param) == 'table' then |
for _, v in pairs(param) do |
for _, v in pairs(param) do |
if (v .. suffix) == name then return true end |
if (v .. suffix) == name then return true end |
end |
end |
return false |
return false |
end |
end |
return ((param .. suffix) == name) |
return ((param .. suffix) == name) |
end |
end |
--[[ |
--[[ |
Check if a value is affirmed (one of the values in L10n.str.affirmedWords) |
Check if a value is affirmed (one of the values in L10n.str.affirmedWords) |
@param {string} val Value to be checked |
@param {string} val Value to be checked |
@returns {boolean} true if affirmed, false otherwise |
@returns {boolean} true if affirmed, false otherwise |
]]-- |
]]-- |
function util.isAffirmed(val) |
function util.isAffirmed(val) |
if not(val) then return false end |
if not(val) then return false end |
return string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or false |
return string.find(L10n.str.affirmedWords, ' '..val..' ', 1, true ) and true or false |
end |
end |
--[[ |
--[[ |
Check if a value is declined (one of the values in L10n.str.declinedWords) |
Check if a value is declined (one of the values in L10n.str.declinedWords) |
@param {string} val Value to be checked |
@param {string} val Value to be checked |
@returns {boolean} true if declined, false otherwise |
@returns {boolean} true if declined, false otherwise |
]]-- |
]]-- |
function util.isDeclined(val) |
function util.isDeclined(val) |
if not(val) then return false end |
if not(val) then return false end |
return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false |
return string.find(L10n.str.declinedWords , ' '..val..' ', 1, true ) and true or false |
end |
end |
--[[ |
--[[ |
Check if the name of a template matches the known coord templates or wrappers |
Check if the name of a template matches the known coord templates or wrappers |
(in L10n.template.coord). The name is normalised when checked, so e.g. the names |
(in L10n.template.coord). The name is normalised when checked, so e.g. the names |
"Coord", "coord", and " Coord" all return true. |
"Coord", "coord", and " Coord" all return true. |
@param {string} name |
@param {string} name |
@returns {boolean} true if it is a coord template or wrapper, false otherwise |
@returns {boolean} true if it is a coord template or wrapper, false otherwise |
]]-- |
]]-- |
function util.isCoordTemplateOrWrapper(name) |
function util.isCoordTemplateOrWrapper(name) |
name = mw.text.trim(name) |
name = mw.text.trim(name) |
local inputTitle = mw.title.new(name, 'Template') |
local inputTitle = mw.title.new(name, 'Template') |
if not inputTitle then |
if not inputTitle then |
return false |
return false |
end |
end |
-- Create (or reuse) mw.title objects for each known coord template/wrapper. |
-- Create (or reuse) mw.title objects for each known coord template/wrapper. |
-- Stored in L10n.template.title so that they don't need to be recreated |
-- Stored in L10n.template.title so that they don't need to be recreated |
-- each time this function is called |
-- each time this function is called |
if not L10n.template.titles then |
if not L10n.template.titles then |
L10n.template.titles = {} |
L10n.template.titles = {} |
for _, v in pairs(L10n.template.coord) do |
for _, v in pairs(L10n.template.coord) do |
table.insert(L10n.template.titles, mw.title.new(v, 'Template')) |
table.insert(L10n.template.titles, mw.title.new(v, 'Template')) |
end |
end |
end |
end |
for _, templateTitle in pairs(L10n.template.titles) do |
for _, templateTitle in pairs(L10n.template.titles) do |
if mw.title.equals(inputTitle, templateTitle) then |
if mw.title.equals(inputTitle, templateTitle) then |
return true |
return true |
end |
end |
end |
end |
return false |
return false |
end |
end |
--[[ |
--[[ |
Recursively extract coord templates which have a name parameter. |
Recursively extract coord templates which have a name parameter. |
@param {string} wikitext |
@param {string} wikitext |
@returns {table} table sequence of coord templates |
@returns {table} table sequence of coord templates |
]]-- |
]]-- |
function util.extractCoordTemplates(wikitext) |
function util.extractCoordTemplates(wikitext) |
local output = {} |
local output = {} |
local templates = mw.ustring.gmatch(wikitext, '{%b{}}') |
local templates = mw.ustring.gmatch(wikitext, '{%b{}}') |
local subtemplates = {} |
local subtemplates = {} |
for template in templates do |
for template in templates do |
local templateName = mw.ustring.match(template, '{{([^}|]+)') |
local templateName = mw.ustring.match(template, '{{([^}|]+)') |
local nameParam = mw.ustring.match(template, "|%s*name%s*=%s*[^}|]+") |
local nameParam = mw.ustring.match(template, "|%s*name%s*=%s*[^}|]+") |
if util.isCoordTemplateOrWrapper(templateName) then |
if util.isCoordTemplateOrWrapper(templateName) then |
if nameParam then table.insert(output, template) end |
if nameParam then table.insert(output, template) end |
elseif mw.ustring.find(mw.ustring.sub(template, 2), "{{") then |
elseif mw.ustring.find(mw.ustring.sub(template, 2), "{{") then |
local subOutput = util.extractCoordTemplates(mw.ustring.sub(template, 2)) |
local subOutput = util.extractCoordTemplates(mw.ustring.sub(template, 2)) |
for _, t in pairs(subOutput) do |
for _, t in pairs(subOutput) do |
table.insert(output, t) |
table.insert(output, t) |
end |
end |
end |
end |
end |
end |
-- ensure coords are not using title display |
-- ensure coords are not using title display |
for k, v in pairs(output) do |
for k, v in pairs(output) do |
output[k] = mw.ustring.gsub(v, "|%s*display%s*=[^|}]+", "|display=inline") |
output[k] = mw.ustring.gsub(v, "|%s*display%s*=[^|}]+", "|display=inline") |
end |
end |
return output |
return output |
end |
end |
--[[ |
--[[ |
Gets all named coordiates from a page or a section of a page. |
Gets all named coordiates from a page or a section of a page. |
@param {string|nil} page Page name, or name#section, to get named coordinates |
@param {string|nil} page Page name, or name#section, to get named coordinates |
from. If the name is omitted, i.e. #section or nil or empty string, then |
from. If the name is omitted, i.e. #section or nil or empty string, then |
the current page will be used. |
the current page will be used. |
@returns {table} sequence of {coord, name, description} tables where coord is |
@returns {table} sequence of {coord, name, description} tables where coord is |
the coordinates in a format suitable for #util.parseCoords, name is a string, |
the coordinates in a format suitable for #util.parseCoords, name is a string, |
and description is a string (coordinates in a format suitable for displaying |
and description is a string (coordinates in a format suitable for displaying |
to the reader). If for some reason the name can't be found, the description |
to the reader). If for some reason the name can't be found, the description |
is nil and the name contains display-format coordinates. |
is nil and the name contains display-format coordinates. |
@throws {L10n.error.noNamedCoords} if no named coordinates are found. |
@throws {L10n.error.noNamedCoords} if no named coordinates are found. |
]]-- |
]]-- |
function util.getNamedCoords(page) |
function util.getNamedCoords(page) |
if transcluder == nil then |
if transcluder == nil then |
-- load [[Module:Transcluder]] lazily so it is only transcluded on pages that |
-- load [[Module:Transcluder]] lazily so it is only transcluded on pages that |
-- actually use named coordinates |
-- actually use named coordinates |
transcluder = require("Module:Transcluder") |
transcluder = require("Module:Transcluder") |
end |
end |
local parts = mw.text.split(page or "", "#", true) |
local parts = mw.text.split(page or "", "#", true) |
local name = parts[1] == "" and mw.title.getCurrentTitle().prefixedText or parts[1] |
local name = parts[1] == "" and mw.title.getCurrentTitle().prefixedText or parts[1] |
local section = parts[2] |
local section = parts[2] |
local pageWikitext = transcluder.get(section and name.."#"..section or name) |
local pageWikitext = transcluder.get(section and name.."#"..section or name) |
local coordTemplates = util.extractCoordTemplates(pageWikitext) |
local coordTemplates = util.extractCoordTemplates(pageWikitext) |
if #coordTemplates == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end |
if #coordTemplates == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end |
local frame = mw.getCurrentFrame() |
local frame = mw.getCurrentFrame() |
local sep = "________" |
local sep = "________" |
local expandedContent = frame:preprocess(table.concat(coordTemplates, sep)) |
local expandedContent = frame:preprocess(table.concat(coordTemplates, sep)) |
local expandedTemplates = mw.text.split(expandedContent, sep) |
local expandedTemplates = mw.text.split(expandedContent, sep) |
local namedCoords = {} |
local namedCoords = {} |
for _, expandedTemplate in pairs(expandedTemplates) do |
for _, expandedTemplate in pairs(expandedTemplates) do |
local coord = mw.ustring.match(expandedTemplate, "<span class=\"geo%-dec\".->(.-)</span>") |
local coord = mw.ustring.match(expandedTemplate, "<span class=\"geo%-dec\".->(.-)</span>") |
if coord then |
if coord then |
local name = ( |
local name = ( |
-- name specified by a wrapper template, e.g [[Article|Name]] |
-- name specified by a wrapper template, e.g [[Article|Name]] |
mw.ustring.match(expandedTemplate, "<span class=\"mapframe%-coord%-name\">(.-)</span>") or |
mw.ustring.match(expandedTemplate, "<span class=\"mapframe%-coord%-name\">(.-)</span>") or |
-- name passed into coord template |
-- name passed into coord template |
mw.ustring.match(expandedTemplate, "<span class=\"fn org\">(.-)</span>") or |
mw.ustring.match(expandedTemplate, "<span class=\"fn org\">(.-)</span>") or |
-- default to the coordinates if the name can't be retrieved |
-- default to the coordinates if the name can't be retrieved |
coord |
coord |
) |
) |
local description = name ~= coord and coord |
local description = name ~= coord and coord |
local coord = mw.ustring.gsub(coord, "[° ]", "_") |
local coord = mw.ustring.gsub(coord, "[° ]", "_") |
table.insert(namedCoords, {coord=coord, name=name, description=description}) |
table.insert(namedCoords, {coord=coord, name=name, description=description}) |
end |
end |
end |
end |
if #namedCoords == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end |
if #namedCoords == 0 then error(string.format(L10n.error.noNamedCoords, page or name), 0) end |
return namedCoords |
return namedCoords |
end |
end |
--[[ |
--[[ |
Parse coordinate values from the params passed in a GeoHack url (such as |
Parse coordinate values from the params passed in a GeoHack url (such as |
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1_2_N_3_4_W_ or |
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1_2_N_3_4_W_ or |
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1.23_S_4.56_E_ ) |
//tools.wmflabs.org/geohack/geohack.php?pagename=Example¶ms=1.23_S_4.56_E_ ) |
or non-url string in the same format (such as `1_2_N_3_4_W_` or `1.23_S_4.56_E_`) |
or non-url string in the same format (such as `1_2_N_3_4_W_` or `1.23_S_4.56_E_`) |
@param {string} coords string containing coordinates |
@param {string} coords string containing coordinates |
@returns {number, number} latitude, longitude |
@returns {number, number} latitude, longitude |
]]-- |
]]-- |
function util.parseCoords(coords) |
function util.parseCoords(coords) |
local coordsPatt |
local coordsPatt |
if mw.ustring.find(coords, "params=", 1, true) then |
if mw.ustring.find(coords, "params=", 1, true) then |
-- prevent false matches from page name, e.g. ?pagename=Lorem_S._Ipsum |
-- prevent false matches from page name, e.g. ?pagename=Lorem_S._Ipsum |
coordsPatt = 'params=([_%.%d]+[NS][_%.%d]+[EW])' |
coordsPatt = 'params=([_%.%d]+[NS][_%.%d]+[EW])' |
else |
else |
-- not actually a geohack url, just the same format |
-- not actually a geohack url, just the same format |
coordsPatt = '[_%.%d]+[NS][_%.%d]+[EW]' |
coordsPatt = '[_%.%d]+[NS][_%.%d]+[EW]' |
end |
end |
local parts = mw.text.split((mw.ustring.match(coords, coordsPatt) or ''), '_') |
local parts = mw.text.split((mw.ustring.match(coords, coordsPatt) or ''), '_') |
local lat_d = tonumber(parts[1]) |
local lat_d = tonumber(parts[1]) |
local lat_m = tonumber(parts[2]) -- nil if coords are in decimal format |
local lat_m = tonumber(parts[2]) -- nil if coords are in decimal format |
local lat_s = lat_m and tonumber(parts[3]) -- nil if coords are either in decimal format or degrees and minutes only |
local lat_s = lat_m and tonumber(parts[3]) -- nil if coords are either in decimal format or degrees and minutes only |
local lat = lat_d + (lat_m or 0)/60 + (lat_s or 0)/3600 |
local lat = lat_d + (lat_m or 0)/60 + (lat_s or 0)/3600 |
if parts[#parts/2] == 'S' then |
if parts[#parts/2] == 'S' then |
lat = lat * -1 |
lat = lat * -1 |
end |
end |
local long_d = tonumber(parts[1+#parts/2]) |
local long_d = tonumber(parts[1+#parts/2]) |
local long_m = tonumber(parts[2+#parts/2]) -- nil if coords are in decimal format |
local long_m = tonumber(parts[2+#parts/2]) -- nil if coords are in decimal format |
local long_s = long_m and tonumber(parts[3+#parts/2]) -- nil if coords are either in decimal format or degrees and minutes only |
local long_s = long_m and tonumber(parts[3+#parts/2]) -- nil if coords are either in decimal format or degrees and minutes only |
local long = long_d + (long_m or 0)/60 + (long_s or 0)/3600 |
local long = long_d + (long_m or 0)/60 + (long_s or 0)/3600 |
if parts[#parts] == 'W' then |
if parts[#parts] == 'W' then |
long = long * -1 |
long = long * -1 |
end |
end |
return lat, long |
return lat, long |
end |
end |
--[[ |
--[[ |
Get coordinates from a Wikidata item |
Get coordinates from a Wikidata item |
@param {string} item_id Wikidata item id (Q number) |
@param {string} item_id Wikidata item id (Q number) |
@returns {number, number} latitude, longitude |
@returns {number, number} latitude, longitude |
@throws {L10n.error.noCoords} if item_id is invalid or the item does not exist |
@throws {L10n.error.noCoords} if item_id is invalid or the item does not exist |
@throws {L10n.error.wikidataCoords} if the the item does not have a P625 |
@throws {L10n.error.wikidataCoords} if the the item does not have a P625 |
statement (coordinates), or it is set to "no value" |
statement (coordinates), or it is set to "no value" |
]]-- |
]]-- |
function util.wikidataCoords(item_id) |
function util.wikidataCoords(item_id) |
if not (item_id and mw.wikibase.isValidEntityId(item_id) and mw.wikibase.entityExists(item_id)) then |
if not (item_id and mw.wikibase.isValidEntityId(item_id) and mw.wikibase.entityExists(item_id)) then |
error(L10n.error.noCoords, 0) |
error(L10n.error.noCoords, 0) |
end |
end |
local coordStatements = mw.wikibase.getBestStatements(item_id, 'P625') |
local coordStatements = mw.wikibase.getBestStatements(item_id, 'P625') |
if not coordStatements or #coordStatements == 0 then |
if not coordStatements or #coordStatements == 0 then |
error(L10n.error.wikidataCoords, 0) |
error(L10n.error.wikidataCoords, 0) |
end |
end |
local hasNoValue = ( coordStatements[1].mainsnak and (coordStatements[1].mainsnak.snaktype == 'novalue' or coordStatements[1].mainsnak.snaktype == 'somevalue') ) |
local hasNoValue = ( coordStatements[1].mainsnak and (coordStatements[1].mainsnak.snaktype == 'novalue' or coordStatements[1].mainsnak.snaktype == 'somevalue') ) |
if hasNoValue then |
if hasNoValue then |
error(L10n.error.wikidataCoords, 0) |
error(L10n.error.wikidataCoords, 0) |
end |
end |
local wdCoords = coordStatements[1]['mainsnak']['datavalue']['value'] |
local wdCoords = coordStatements[1]['mainsnak']['datavalue']['value'] |
return tonumber(wdCoords['latitude']), tonumber(wdCoords['longitude']) |
return tonumber(wdCoords['latitude']), tonumber(wdCoords['longitude']) |
end |
end |
--[[ |
--[[ |
Creates a polygon that approximates a circle |
Creates a polygon that approximates a circle |
@param {number} lat Latitude |
@param {number} lat Latitude |
@param {number} long Longitude |
@param {number} long Longitude |
@param {number} radius Radius in metres |
@param {number} radius Radius in metres |
@param {number} n Number of edges for the polygon |
@param {number} n Number of edges for the polygon |
@returns {table} sequence of {latitude, longitude} table sequences, where |
@returns {table} sequence of {latitude, longitude} table sequences, where |
latitude and longitude are both numbers |
latitude and longitude are both numbers |
]]-- |
]]-- |
function util.circleToPolygon(lat, long, radius, n) -- n is number of edges |
function util.circleToPolygon(lat, long, radius, n) -- n is number of edges |
-- Based on https://github.com/gabzim/circle-to-polygon, ISC licence |
-- Based on https://github.com/gabzim/circle-to-polygon, ISC licence |
local function offset(cLat, cLon, distance, bearing) |
local function offset(cLat, cLon, distance, bearing) |
local lat1 = math.rad(cLat) |
local lat1 = math.rad(cLat) |
local lon1 = math.rad(cLon) |
local lon1 = math.rad(cLon) |
local dByR = distance / 6378137 -- distance divided by 6378137 (radius of the earth) wgs84 |
local dByR = distance / 6378137 -- distance divided by 6378137 (radius of the earth) wgs84 |
local lat = math.asin( |
local lat = math.asin( |
math.sin(lat1) * math.cos(dByR) + |
math.sin(lat1) * math.cos(dByR) + |
math.cos(lat1) * math.sin(dByR) * math.cos(bearing) |
math.cos(lat1) * math.sin(dByR) * math.cos(bearing) |
) |
) |
local lon = lon1 + math.atan2( |
local lon = lon1 + math.atan2( |
math.sin(bearing) * math.sin(dByR) * math.cos(lat1), |
math.sin(bearing) * math.sin(dByR) * math.cos(lat1), |
math.cos(dByR) - math.sin(lat1) * math.sin(lat) |
math.cos(dByR) - math.sin(lat1) * math.sin(lat) |
) |
) |
return {math.deg(lon), math.deg(lat)} |
return {math.deg(lon), math.deg(lat)} |
end |
end |
local coordinates = {}; |
local coordinates = {}; |
local i = 0; |
local i = 0; |
while i < n do |
while i < n do |
table.insert(coordinates, |
table.insert(coordinates, |
offset(lat, long, radius, (2*math.pi*i*-1)/n) |
offset(lat, long, radius, (2*math.pi*i*-1)/n) |
) |
) |
i = i + 1 |
i = i + 1 |
end |
end |
table.insert(coordinates, offset(lat, long, radius, 0)) |
table.insert(coordinates, offset(lat, long, radius, 0)) |
return coordinates |
return coordinates |
end |
end |
--[[ |
--[[ |
Get the number of key-value pairs in a table, which might not be a sequence. |
Get the number of key-value pairs in a table, which might not be a sequence. |
@param {table} t |
@param {table} t |
@returns {number} count of key-value pairs |
@returns {number} count of key-value pairs |
]]-- |
]]-- |
function util.tableCount(t) |
function util.tableCount(t) |
local count = 0 |
local count = 0 |
for k, v in pairs(t) do |
for k, v in pairs(t) do |
count = count + 1 |
count = count + 1 |
end |
end |
return count |
return count |
end |
end |
--[[ |
--[[ |
For a table where the values are all tables, returns either the util.tableCount |
For a table where the values are all tables, returns either the util.tableCount |
of the subtables if they are all the same, or nil if they are not all the same. |
of the subtables if they are all the same, or nil if they are not all the same. |
@param {table} t |
@param {table} t |
@returns {number|nil} count of key-value pairs of subtable, or nil if subtables |
@returns {number|nil} count of key-value pairs of subtable, or nil if subtables |
have different counts |
have different counts |
]]-- |
]]-- |
function util.subTablesCount(t) |
function util.subTablesCount(t) |
local count = nil |
local count = nil |
for k, v in pairs(t) do |
for k, v in pairs(t) do |
if count == nil then |
if count == nil then |
count = util.tableCount(v) |
count = util.tableCount(v) |
elseif count ~= util.tableCount(v) then |
elseif count ~= util.tableCount(v) then |
return nil |
return nil |
end |
end |
end |
end |
return count |
return count |
end |
end |
--[[ |
--[[ |
Splits a list into a table sequence. The items in the list may be separated by |
Splits a list into a table sequence. The items in the list may be separated by |
commas, or by semicolons (if items may contain commas), or by "###" (if items |
commas, or by semicolons (if items may contain commas), or by "###" (if items |
may contain semicolons). |
may contain semicolons). |
@param {string} listString |
@param {string} listString |
@returns {table} sequence of list items |
@returns {table} sequence of list items |
]]-- |
]]-- |
function util.tableFromList(listString) |
function util.tableFromList(listString) |
if type(listString) ~= "string" or listString == "" then return nil end |
if type(listString) ~= "string" or listString == "" then return nil end |
local separator = (mw.ustring.find(listString, "###", 0, true ) and "###") or |
local separator = (mw.ustring.find(listString, "###", 0, true ) and "###") or |
(mw.ustring.find(listString, ";", 0, true ) and ";") or "," |
(mw.ustring.find(listString, ";", 0, true ) and ";") or "," |
local pattern = "%s*"..separator.."%s*" |
local pattern = "%s*"..separator.."%s*" |
return mw.text.split(listString, pattern) |
return mw.text.split(listString, pattern) |
end |
end |
-- Boolean in outer scope indicating if Kartographer should be able to |
-- Boolean in outer scope indicating if Kartographer should be able to |
-- automatically calculate coordinates (see phab:T227402) |
-- automatically calculate coordinates (see phab:T227402) |
local coordsDerivedFromFeatures = false; |
local coordsDerivedFromFeatures = false; |
--[[---------------------------------------------------------------------------- |
--[[---------------------------------------------------------------------------- |
Make methods: These take in a table of arguments, and return either a string |
Make methods: These take in a table of arguments, and return either a string |
or a table to be used in the eventual output. |
or a table to be used in the eventual output. |
----------------------------------------------------------------------------]]-- |
----------------------------------------------------------------------------]]-- |
local make = {} |
local make = {} |
--[[ |
--[[ |
Makes content to go inside the maplink or mapframe tag. |
Makes content to go inside the maplink or mapframe tag. |
@param {table} args |
@param {table} args |
@returns {string} tag content |
@returns {string} tag content |
]]-- |
]]-- |
function make.content(args) |
function make.content(args) |
if util.getParameterValue(args, 'raw') then |
if util.getParameterValue(args, 'raw') then |
coordsDerivedFromFeatures = true -- Kartographer should be able to automatically calculate coords from raw geoJSON |
coordsDerivedFromFeatures = true -- Kartographer should be able to automatically calculate coords from raw geoJSON |
return util.getParameterValue(args, 'raw') |
return util.getParameterValue(args, 'raw') |
end |
end |
local content = {} |
local content = {} |
local argsExpanded = {} |
local argsExpanded = {} |
for k, v in pairs(args) do |
for k, v in pairs(args) do |
local index = string.match( k, '^[^0-9]+([0-9]*)$' ) |
local index = string.match( k, '^[^0-9]+([0-9]*)$' ) |
if index ~= nil then |
if index ~= nil then |
local indexNumber = '' |
local indexNumber = '' |
if index ~= '' then |
if index ~= '' then |
indexNumber = tonumber(index) |
indexNumber = tonumber(index) |
else |
else |
indexNumber = 1 |
indexNumber = 1 |
end |
end |
if argsExpanded[indexNumber] == nil then |
if argsExpanded[indexNumber] == nil then |
argsExpanded[indexNumber] = {} |
argsExpanded[indexNumber] = {} |
end |
end |
argsExpanded[indexNumber][ string.gsub(k, index, '') ] = v |
argsExpanded[indexNumber][ string.gsub(k, index, '') ] = v |
end |
end |
end |
end |
for contentIndex, contentArgs in pairs(argsExpanded) do |
for contentIndex, contentArgs in pairs(argsExpanded) do |
local argType = util.getParameterValue(contentArgs, "type") |
local argType = util.getParameterValue(contentArgs, "type") |
-- Kartographer automatically calculates coords if geolines/shapes are used (T227402) |
-- Kartographer automatically calculates coords if geolines/shapes are used (T227402) |
if not coordsDerivedFromFeatures then |
if not coordsDerivedFromFeatures then |
coordsDerivedFromFeatures = ( argType == L10n.str.line or argType == L10n.str.shape ) and true or false |
coordsDerivedFromFeatures = ( argType == L10n.str.line or argType == L10n.str.shape ) and true or false |
end |
end |
if argType == L10n.str.named then |
if argType == L10n.str.named then |
local namedCoords = util.getNamedCoords(util.getParameterValue(contentArgs, "from")) |
local namedCoords = util.getNamedCoords(util.getParameterValue(contentArgs, "from")) |
local typeKey = type(L10n.para.type) == "table" and L10n.para.type[1] or L10n.para.type |
local typeKey = type(L10n.para.type) == "table" and L10n.para.type[1] or L10n.para.type |
local coordKey = type(L10n.para.coord) == "table" and L10n.para.coord[1] or L10n.para.coord |
local coordKey = type(L10n.para.coord) == "table" and L10n.para.coord[1] or L10n.para.coord |
local titleKey = type(L10n.para.title) == "table" and L10n.para.title[1] or L10n.para.title |
local titleKey = type(L10n.para.title) == "table" and L10n.para.title[1] or L10n.para.title |
local descKey = type(L10n.para.description) == "table" and L10n.para.description[1] or L10n.para.description |
local descKey = type(L10n.para.description) == "table" and L10n.para.description[1] or L10n.para.description |
for _, namedCoord in pairs(namedCoords) do |
for _, namedCoord in pairs(namedCoords) do |
contentArgs[typeKey] = "point" |
contentArgs[typeKey] = "point" |
contentArgs[coordKey] = namedCoord.coord |
contentArgs[coordKey] = namedCoord.coord |
contentArgs[titleKey] = namedCoord.name |
contentArgs[titleKey] = namedCoord.name |
contentArgs[descKey] = namedCoord.description |
contentArgs[descKey] = namedCoord.description |
content[#content+1] = make.contentJson(contentArgs) |
content[#content+1] = make.contentJson(contentArgs) |
end |
end |
else |
else |
content[#content + 1] = make.contentJson(contentArgs) |
content[#content + 1] = make.contentJson(contentArgs) |
end |
end |
end |
end |
--Single item, no array needed |
--Single item, no array needed |
if #content==1 then return content[1] end |
if #content==1 then return content[1] end |
--Multiple items get placed in a FeatureCollection |
--Multiple items get placed in a FeatureCollection |
local contentArray = '[\n' .. table.concat( content, ',\n') .. '\n]' |
local contentArray = '[\n' .. table.concat( content, ',\n') .. '\n]' |
return contentArray |
return contentArray |
end |
end |
--[[ |
--[[ |
Make coordinates from the coord arg, or the id arg, or the current page's |
Make coordinates from the coord arg, or the id arg, or the current page's |
Wikidata item. |
Wikidata item. |
@param {table} args |
@param {table} args |
@param {boolean} [plainOutput] |
@param {boolean} [plainOutput] |
@returns {Mixed} Either: |
@returns {Mixed} Either: |
{number, number} latitude, longitude if plainOutput is true; or |
{number, number} latitude, longitude if plainOutput is true; or |
{table} table sequence of longitude, then latitude (gives the required format |
{table} table sequence of longitude, then latitude (gives the required format |
for GeoJSON when encoded) |
for GeoJSON when encoded) |
]]-- |
]]-- |
function make.coords(args, plainOutput) |
function make.coords(args, plainOutput) |
local coords, lat, long |
local coords, lat, long |
local frame = mw.getCurrentFrame() |
local frame = mw.getCurrentFrame() |
if util.getParameterValue(args, 'coord') then |
if util.getParameterValue(args, 'coord') then |
coords = frame:preprocess( util.getParameterValue(args, 'coord') ) |
coords = frame:preprocess( util.getParameterValue(args, 'coord') ) |
lat, long = util.parseCoords(coords) |
lat, long = util.parseCoords(coords) |
else |
else |
lat, long = util.wikidataCoords(util.getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) |
lat, long = util.wikidataCoords(util.getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) |
end |
end |
if plainOutput then |
if plainOutput then |
return lat, long |
return lat, long |
end |
end |
return {[0] = long, [1] = lat} |
return {[0] = long, [1] = lat} |
end |
end |
--[[ |
--[[ |
Makes a table of coordinates that approximate a circle. |
Makes a table of coordinates that approximate a circle. |
@param {table} args |
@param {table} args |
@returns {table} sequence of {latitude, longitude} table sequences, where |
@returns {table} sequence of {latitude, longitude} table sequences, where |
latitude and longitude are both numbers |
latitude and longitude are both numbers |
@throws {L10n.error.noCircleCoords} if centre coordinates are not specified |
@throws {L10n.error.noCircleCoords} if centre coordinates are not specified |
@throws {L10n.error.noRadius} if radius is not specified |
@throws {L10n.error.noRadius} if radius is not specified |
@throws {L10n.error.negativeRadius} if radius is negative or zero |
@throws {L10n.error.negativeRadius} if radius is negative or zero |
@throws {L10n.error.negativeEdges} if edges is negative or zero |
@throws {L10n.error.negativeEdges} if edges is negative or zero |
]]-- |
]]-- |
function make.circleCoords(args) |
function make.circleCoords(args) |
local lat, long = make.coords(args, true) |
local lat, long = make.coords(args, true) |
local radius = util.getParameterValue(args, 'radius') |
local radius = util.getParameterValue(args, 'radius') |
if not radius then |
if not radius then |
radius = util.getParameterValue(args, 'radiusKm') and tonumber(util.getParameterValue(args, 'radiusKm'))*1000 |
radius = util.getParameterValue(args, 'radiusKm') and tonumber(util.getParameterValue(args, 'radiusKm'))*1000 |
if not radius then |
if not radius then |
radius = util.getParameterValue(args, 'radiusMi') and tonumber(util.getParameterValue(args, 'radiusMi'))*1609.344 |
radius = util.getParameterValue(args, 'radiusMi') and tonumber(util.getParameterValue(args, 'radiusMi'))*1609.344 |
if not radius then |
if not radius then |
radius = util.getParameterValue(args, 'radiusFt') and tonumber(util.getParameterValue(args, 'radiusFt'))*0.3048 |
radius = util.getParameterValue(args, 'radiusFt') and tonumber(util.getParameterValue(args, 'radiusFt'))*0.3048 |
end |
end |
end |
end |
end |
end |
local edges = util.getParameterValue(args, 'edges') or L10n.defaults.edges |
local edges = util.getParameterValue(args, 'edges') or L10n.defaults.edges |
if not lat or not long then |
if not lat or not long then |
error(L10n.error.noCircleCoords, 0) |
error(L10n.error.noCircleCoords, 0) |
elseif not radius then |
elseif not radius then |
error(L10n.error.noRadius, 0) |
error(L10n.error.noRadius, 0) |
elseif tonumber(radius) <= 0 then |
elseif tonumber(radius) <= 0 then |
error(L10n.error.negativeRadius, 0) |
error(L10n.error.negativeRadius, 0) |
elseif tonumber(edges) <= 0 then |
elseif tonumber(edges) <= 0 then |
error(L10n.error.negativeEdges, 0) |
error(L10n.error.negativeEdges, 0) |
end |
end |
return util.circleToPolygon(lat, long, radius, tonumber(edges)) |
return util.circleToPolygon(lat, long, radius, tonumber(edges)) |
end |
end |
--[[ |
--[[ |
Makes JSON data for a feature |
Makes JSON data for a feature |
@param contentArgs args for this feature. Keys must be the non-suffixed version |
@param contentArgs args for this feature. Keys must be the non-suffixed version |
of the parameter names, i.e. use type, stroke, fill,... rather than type3, |
of the parameter names, i.e. use type, stroke, fill,... rather than type3, |
stroke3, fill3,... |
stroke3, fill3,... |
@returns {string} JSON encoded data |
@returns {string} JSON encoded data |
]]-- |
]]-- |
function make.contentJson(contentArgs) |
function make.contentJson(contentArgs) |
local data = {} |
local data = {} |
if util.getParameterValue(contentArgs, 'type') == L10n.str.point or util.getParameterValue(contentArgs, 'type') == L10n.str.circle then |
if util.getParameterValue(contentArgs, 'type') == L10n.str.point or util.getParameterValue(contentArgs, 'type') == L10n.str.circle then |
local isCircle = util.getParameterValue(contentArgs, 'type') == L10n.str.circle |
local isCircle = util.getParameterValue(contentArgs, 'type') == L10n.str.circle |
data.type = "Feature" |
data.type = "Feature" |
data.geometry = { |
data.geometry = { |
type = isCircle and "LineString" or "Point", |
type = isCircle and "LineString" or "Point", |
coordinates = isCircle and make.circleCoords(contentArgs) or make.coords(contentArgs) |
coordinates = isCircle and make.circleCoords(contentArgs) or make.coords(contentArgs) |
} |
} |
data.properties = { |
data.properties = { |
title = util.getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle() |
title = util.getParameterValue(contentArgs, 'title') or mw.getCurrentFrame():getParent():getTitle() |
} |
} |
if isCircle then |
if isCircle then |
-- TODO: This is very similar to below, should be extracted into a function |
-- TODO: This is very similar to below, should be extracted into a function |
data.properties.stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor |
data.properties.stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor |
data.properties["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth |
data.properties["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth |
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity') |
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity') |
if strokeOpacity then |
if strokeOpacity then |
data.properties['stroke-opacity'] = tonumber(strokeOpacity) |
data.properties['stroke-opacity'] = tonumber(strokeOpacity) |
end |
end |
local fill = util.getParameterValue(contentArgs, 'fill') |
local fill = util.getParameterValue(contentArgs, 'fill') |
if fill then |
if fill then |
data.properties.fill = fill |
data.properties.fill = fill |
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity') |
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity') |
data.properties['fill-opacity'] = fillOpacity and tonumber(fillOpacity) or 0.6 |
data.properties['fill-opacity'] = fillOpacity and tonumber(fillOpacity) or 0.6 |
end |
end |
else -- is a point |
else -- is a point |
local markerSymbol = util.getParameterValue(contentArgs, 'marker') or L10n.defaults.marker |
local markerSymbol = util.getParameterValue(contentArgs, 'marker') or L10n.defaults.marker |
-- allow blank to be explicitly specified, for overriding infoboxes or other templates with a default value |
-- allow blank to be explicitly specified, for overriding infoboxes or other templates with a default value |
if markerSymbol ~= "blank" then |
if markerSymbol ~= "blank" then |
data.properties["marker-symbol"] = markerSymbol |
data.properties["marker-symbol"] = markerSymbol |
end |
end |
data.properties["marker-color"] = util.getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor |
data.properties["marker-color"] = util.getParameterValue(contentArgs, 'markerColor') or L10n.defaults.markerColor |
data.properties["marker-size"] = util.getParameterValue(contentArgs, 'markerSize') or L10n.defaults.markerSize |
data.properties["marker-size"] = util.getParameterValue(contentArgs, 'markerSize') or L10n.defaults.markerSize |
end |
end |
else |
else |
data.type = "ExternalData" |
data.type = "ExternalData" |
if util.getParameterValue(contentArgs, 'type') == L10n.str.data or util.getParameterValue(contentArgs, 'from') then |
if util.getParameterValue(contentArgs, 'type') == L10n.str.data or util.getParameterValue(contentArgs, 'from') then |
data.service = "page" |
data.service = "page" |
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.line then |
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.line then |
data.service = "geoline" |
data.service = "geoline" |
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shape then |
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shape then |
data.service = "geoshape" |
data.service = "geoshape" |
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse then |
elseif util.getParameterValue(contentArgs, 'type') == L10n.str.shapeInverse then |
data.service = "geomask" |
data.service = "geomask" |
end |
end |
if util.getParameterValue(contentArgs, 'id') or (not (util.getParameterValue(contentArgs, 'from')) and mw.wikibase.getEntityIdForCurrentPage()) then |
if util.getParameterValue(contentArgs, 'id') or (not (util.getParameterValue(contentArgs, 'from')) and mw.wikibase.getEntityIdForCurrentPage()) then |
data.ids = util.getParameterValue(contentArgs, 'id') or mw.wikibase.getEntityIdForCurrentPage() |
data.ids = util.getParameterValue(contentArgs, 'id') or mw.wikibase.getEntityIdForCurrentPage() |
else |
else |
data.title = util.getParameterValue(contentArgs, 'from') |
data.title = util.getParameterValue(contentArgs, 'from') |
end |
end |
data.properties = { |
data.properties = { |
stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor, |
stroke = util.getParameterValue(contentArgs, 'strokeColor') or L10n.defaults.strokeColor, |
["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth |
["stroke-width"] = tonumber(util.getParameterValue(contentArgs, 'strokeWidth')) or L10n.defaults.strokeWidth |
} |
} |
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity') |
local strokeOpacity = util.getParameterValue(contentArgs, 'strokeOpacity') |
if strokeOpacity then |
if strokeOpacity then |
data.properties['stroke-opacity'] = tonumber(strokeOpacity) |
data.properties['stroke-opacity'] = tonumber(strokeOpacity) |
end |
end |
local fill = util.getParameterValue(contentArgs, 'fill') |
local fill = util.getParameterValue(contentArgs, 'fill') |
if fill and (data.service == "geoshape" or data.service == "geomask") then |
if fill and (data.service == "geoshape" or data.service == "geomask") then |
data.properties.fill = fill |
data.properties.fill = fill |
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity') |
local fillOpacity = util.getParameterValue(contentArgs, 'fillOpacity') |
if fillOpacity then |
if fillOpacity then |
data.properties['fill-opacity'] = tonumber(fillOpacity) |
data.properties['fill-opacity'] = tonumber(fillOpacity) |
end |
end |
end |
end |
end |
end |
data.properties.title = util.getParameterValue(contentArgs, 'title') or mw.title.getCurrentTitle().text |
data.properties.title = util.getParameterValue(contentArgs, 'title') or mw.title.getCurrentTitle().text |
if util.getParameterValue(contentArgs, 'description') then |
if util.getParameterValue(contentArgs, 'description') then |
data.properties.description = util.getParameterValue(contentArgs, 'description') |
data.properties.description = util.getParameterValue(contentArgs, 'description') |
end |
end |
return mw.text.jsonEncode(data) |
return mw.text.jsonEncode(data) |
end |
end |
--[[ |
--[[ |
Makes attributes for the maplink or mapframe tag. |
Makes attributes for the maplink or mapframe tag. |
@param {table} args |
@param {table} args |
@param {boolean} [isTitle] Tag is to be displayed in the title of page rather |
@param {boolean} [isTitle] Tag is to be displayed in the title of page rather |
than inline |
than inline |
@returns {table<string,string>} key-value pairs of attribute names and values |
@returns {table<string,string>} key-value pairs of attribute names and values |
]]-- |
]]-- |
function make.tagAttribs(args, isTitle) |
function make.tagAttribs(args, isTitle) |
local attribs = {} |
local attribs = {} |
if util.getParameterValue(args, 'zoom') then |
if util.getParameterValue(args, 'zoom') then |
attribs.zoom = util.getParameterValue(args, 'zoom') |
attribs.zoom = util.getParameterValue(args, 'zoom') |
end |
end |
if util.isDeclined(util.getParameterValue(args, 'icon')) then |
if util.isDeclined(util.getParameterValue(args, 'icon')) then |
attribs.class = "no-icon" |
attribs.class = "no-icon" |
end |
end |
if util.getParameterValue(args, 'type') == L10n.str.point and not coordsDerivedFromFeatures then |
if util.getParameterValue(args, 'type') == L10n.str.point and not coordsDerivedFromFeatures then |
local lat, long = make.coords(args, 'plainOutput') |
local lat, long = make.coords(args, 'plainOutput') |
attribs.latitude = tostring(lat) |
attribs.latitude = tostring(lat) |
attribs.longitude = tostring(long) |
attribs.longitude = tostring(long) |
end |
end |
if util.isAffirmed(util.getParameterValue(args, 'frame')) and not(isTitle) then |
if util.isAffirmed(util.getParameterValue(args, 'frame')) and not(isTitle) then |
attribs.width = util.getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidth |
attribs.width = util.getParameterValue(args, 'frameWidth') or L10n.defaults.frameWidth |
attribs.height = util.getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeight |
attribs.height = util.getParameterValue(args, 'frameHeight') or L10n.defaults.frameHeight |
if util.getParameterValue(args, 'frameCoordinates') then |
if util.getParameterValue(args, 'frameCoordinates') then |
local frameLat, frameLong = util.parseCoords(util.getParameterValue(args, 'frameCoordinates')) |
local frameLat, frameLong = util.parseCoords(util.getParameterValue(args, 'frameCoordinates')) |
attribs.latitude = frameLat |
attribs.latitude = frameLat |
attribs.longitude = frameLong |
attribs.longitude = frameLong |
else |
else |
if util.getParameterValue(args, 'frameLatitude') then |
if util.getParameterValue(args, 'frameLatitude') then |
attribs.latitude = util.getParameterValue(args, 'frameLatitude') |
attribs.latitude = util.getParameterValue(args, 'frameLatitude') |
end |
end |
if util.getParameterValue(args, 'frameLongitude') then |
if util.getParameterValue(args, 'frameLongitude') then |
attribs.longitude = util.getParameterValue(args, 'frameLongitude') |
attribs.longitude = util.getParameterValue(args, 'frameLongitude') |
end |
end |
end |
end |
if not attribs.latitude and not attribs.longitude and not coordsDerivedFromFeatures then |
if not attribs.latitude and not attribs.longitude and not coordsDerivedFromFeatures then |
local success, lat, long = pcall(util.wikidataCoords, util.getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) |
local success, lat, long = pcall(util.wikidataCoords, util.getParameterValue(args, 'id') or mw.wikibase.getEntityIdForCurrentPage()) |
if success then |
if success then |
attribs.latitude = tostring(lat) |
attribs.latitude = tostring(lat) |
attribs.longitude = tostring(long) |
attribs.longitude = tostring(long) |
end |
end |
end |
end |
if util.getParameterValue(args, 'frameAlign') then |
if util.getParameterValue(args, 'frameAlign') then |
attribs.align = util.getParameterValue(args, 'frameAlign') |
attribs.align = util.getParameterValue(args, 'frameAlign') |
end |
end |
if util.isAffirmed(util.getParameterValue(args, 'plain')) then |
if util.isAffirmed(util.getParameterValue(args, 'plain')) then |
attribs.frameless = "1" |
attribs.frameless = "1" |
else |
else |
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text |
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text |
end |
end |
else |
else |
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text |
attribs.text = util.getParameterValue(args, 'text') or L10n.defaults.text |
end |
end |
return attribs |
return attribs |
end |
end |
--[[ |
--[[ |
Makes maplink wikitext that will be located in the top-right of the title of the |
Makes maplink wikitext that will be located in the top-right of the title of the |
page (the same place where coords with |display=title are positioned). |
page (the same place where coords with |display=title are positioned). |
@param {table} args |
@param {table} args |
@param {string} tagContent Content for the maplink tag |
@param {string} tagContent Content for the maplink tag |
@returns {string} |
@returns {string} |
]]-- |
]]-- |
function make.titleOutput(args, tagContent) |
function make.titleOutput(args, tagContent) |
local titleTag = mw.text.tag('maplink', make.tagAttribs(args, true), tagContent) |
local titleTag = mw.text.tag('maplink', make.tagAttribs(args, true), tagContent) |
local spanAttribs = { |
local spanAttribs = { |
style = "font-size: small;", |
style = "font-size: small;", |
id = "coordinates" |
id = "coordinates" |
} |
} |
return mw.text.tag('span', spanAttribs, titleTag) |
return mw.text.tag('span', spanAttribs, titleTag) |
end |
end |
--[[ |
--[[ |
Makes maplink or mapframe wikitext that will be located inline. |
Makes maplink or mapframe wikitext that will be located inline. |
@param {table} args |
@param {table} args |
@param {string} tagContent Content for the maplink tag |
@param {string} tagContent Content for the maplink tag |
@returns {string} |
@returns {string} |
]]-- |
]]-- |
function make.inlineOutput(args, tagContent) |
function make.inlineOutput(args, tagContent) |
local tagName = 'maplink' |
local tagName = 'maplink' |
if util.getParameterValue(args, 'frame') then |
if util.getParameterValue(args, 'frame') then |
tagName = 'mapframe' |
tagName = 'mapframe' |
end |
end |
return mw.text.tag(tagName, make.tagAttribs(args), tagContent) |
return mw.text.tag(tagName, make.tagAttribs(args), tagContent) |
end |
end |
--[[ |
--[[ |
Makes the HTML required for the swicther to work, including the templatestyles |
Makes the HTML required for the swicther to work, including the templatestyles |
tag. |
tag. |
@param {table} params table sequence of {map, label} tables |
@param {table} params table sequence of {map, label} tables |
@param {string} params{}.map Wikitext for mapframe map |
@param {string} params{}.map Wikitext for mapframe map |
@param {string} params{}.label Label text for swicther option |
@param {string} params{}.label Label text for swicther option |
@param {table} options |
@param {table} options |
@param {string} options.alignment "left" or "center" or "right" |
@param {string} options.alignment "left" or "center" or "right" |
@param {boolean} options.isThumbnail Display in a thumbnail |
@param {boolean} options.isThumbnail Display in a thumbnail |
@param {string} options.width Width of frame, e.g. "200" |
@param {string} options.width Width of frame, e.g. "200" |
@param {string} [options.caption] Caption wikitext for thumnail |
@param {string} [options.caption] Caption wikitext for thumnail |
@retruns {string} swicther HTML |
@retruns {string} swicther HTML |
]]-- |
]]-- |
function make.switcherHtml(params, options) |
function make.switcherHtml(params, options) |
options = options or {} |
options = options or {} |
local frame = mw.getCurrentFrame() |
local frame = mw.getCurrentFrame() |
local styles = frame:extensionTag{ |
local styles = frame:extensionTag{ |
name = "templatestyles", |
name = "templatestyles", |
args = {src = "Template:Maplink/styles-multi.css"} |
args = {src = "Template:Maplink/styles-multi.css"} |
} |
} |
local container = mw.html.create("div") |
local container = mw.html.create("div") |
:addClass("switcher-container") |
:addClass("switcher-container") |
:addClass("mapframe-multi-container") |
:addClass("mapframe-multi-container") |
if options.alignment == "left" or options.alignment == "right" then |
if options.alignment == "left" or options.alignment == "right" then |
container:addClass("float"..options.alignment) |
container:addClass("float"..options.alignment) |
else -- alignment is "center" |
else -- alignment is "center" |
container:addClass("center") |
container:addClass("center") |
end |
end |
for i = 1, #params do |
for i = 1, #params do |
container |
container |
:tag("div") |
:tag("div") |
:wikitext(params[i].map) |
:wikitext(params[i].map) |
:tag("span") |
:tag("span") |
:addClass("switcher-label") |
:addClass("switcher-label") |
:css("display", "none") |
:css("display", "none") |
:wikitext(mw.text.trim(params[i].label)) |
:wikitext(mw.text.trim(params[i].label)) |
end |
end |
if not options.isThumbnail then |
if not options.isThumbnail then |
return styles .. tostring(container) |
return styles .. tostring(container) |
end |
end |
local classlist = container:getAttr("class") |
local classlist = container:getAttr("class") |
classlist = mw.ustring.gsub(classlist, "%a*"..options.alignment, "") |
classlist = mw.ustring.gsub(classlist, "%a*"..options.alignment, "") |
container:attr("class", classlist) |
container:attr("class", classlist) |
local outerCountainer = mw.html.create("div") |
local outerCountainer = mw.html.create("div") |
:addClass("mapframe-multi-outer-container") |
:addClass("mapframe-multi-outer-container") |
:addClass("mw-kartographer-container") |
:addClass("mw-kartographer-container") |
:addClass("thumb") |
:addClass("thumb") |
if options.alignment == "left" or options.alignment == "right" then |
if options.alignment == "left" or options.alignment == "right" then |
outerCountainer:addClass("t"..options.alignment) |
outerCountainer:addClass("t"..options.alignment) |
else -- alignment is "center" |
else -- alignment is "center" |
outerCountainer |
outerCountainer |
:addClass("tnone") |
:addClass("tnone") |
:addClass("center") |
:addClass("center") |
end |
end |
outerCountainer |
outerCountainer |
:tag("div") |
:tag("div") |
:addClass("thumbinner") |
:addClass("thumbinner") |
:css("width", options.width.."px") |
:css("width", options.width.."px") |
:node(container) |
:node(container) |
:node(options.caption and mw.html.create("div") |
:node(options.caption and mw.html.create("div") |
:addClass("thumbcaption") |
:addClass("thumbcaption") |
:wikitext(options.caption) |
:wikitext(options.caption) |
) |
) |
return styles .. tostring(outerCountainer) |
return styles .. tostring(outerCountainer) |
end |
end |
--[[ |
--[[ |
Makes the HTML required for an overlay map to work |
Makes the HTML required for an overlay map to work |
tag. |
tag. |
@param {string} overlayMap wikitext for the overlay map |
@param {string} overlayMap wikitext for the overlay map |
@param {string} baseMap wikitext for the base map |
@param {string} baseMap wikitext for the base map |
@param {table} options various styling/display options |
@param {table} options various styling/display options |
@param {string} options.align "left" or "center" or "right" |
@param {string} options.align "left" or "center" or "right" |
@param {string|number} options.width Width of the base map, e.g. "300" |
@param {string|number} options.width Width of the base map, e.g. "300" |
@param {string|number} options.width Height of the base map, e.g. "200" |
@param {string|number} options.width Height of the base map, e.g. "200" |
@param {string} options.border Border style for the overlayed map, e.g. "1px solid white" |
@param {string} options.border Border style for the overlayed map, e.g. "1px solid white" |
@param {string} options.horizontalAlignment Horizontal alignment for overlay map, "left" or "right" |
@param {string} options.horizontalAlignment Horizontal alignment for overlay map, "left" or "right" |
@param {string|number} options.horizontalOffset Horizontal offset in pixels from the alignment edge, e.g "10" |
@param {string|number} options.horizontalOffset Horizontal offset in pixels from the alignment edge, e.g "10" |
@param {string} options.verticalAlignment Vertical alignment for overlay map, "top" or "bottom" |
@param {string} options.verticalAlignment Vertical alignment for overlay map, "top" or "bottom" |
@param {string|number} options.verticalOffset Vertical offset in pixels from the alignment edge, e.g. is "10" |
@param {string|number} options.verticalOffset Vertical offset in pixels from the alignment edge, e.g. is "10" |
@param {boolean} options.isThumbnail Display in a thumbnail |
@param {boolean} options.isThumbnail Display in a thumbnail |
@param {string} [options.caption] Caption wikitext for thumnail |
@param {string} [options.caption] Caption wikitext for thumnail |
@retruns {string} HTML for basemap with overlay |
@retruns {string} HTML for basemap with overlay |
]]-- |
]]-- |
function make.overlayHtml(overlayMap, baseMap, options) |
function make.overlayHtml(overlayMap, baseMap, options) |
options = options or {} |
options = options or {} |
local containerFloatClass = "float"..(options.align or "none") |
local containerFloatClass = "float"..(options.align or "none") |
if options.align == "center" then |
if options.align == "center" then |
containerFloatClass = "center" |
containerFloatClass = "center" |
end |
end |
local containerStyle = { |
local containerStyle = { |
position = "relative", |
position = "relative", |
width = options.width .. "px", |
width = options.width .. "px", |
height = options.height .. "px", |
height = options.height .. "px", |
overflow = "hidden" -- mobile/minerva tends to add scrollbars for a couple of pixels |
overflow = "hidden" -- mobile/minerva tends to add scrollbars for a couple of pixels |
} |
} |
if options.align == "center" then |
if options.align == "center" then |
containerStyle["margin-left"] = "auto" |
containerStyle["margin-left"] = "auto" |
containerStyle["margin-right"] = "auto" |
containerStyle["margin-right"] = "auto" |
end |
end |
local container = mw.html.create("div") |
local container = mw.html.create("div") |
:addClass("mapframe-withOverlay-container") |
:addClass("mapframe-withOverlay-container") |
:addClass(containerFloatClass) |
:addClass(containerFloatClass) |
:addClass("noresize") |
:addClass("noresize") |
:css(containerStyle) |
:css(containerStyle) |
local overlayStyle = { |
local overlayStyle = { |
position = "absolute", |
position = "absolute", |
["z-index"] = "1", |
["z-index"] = "1", |
border = options.border or "1px solid white" |
border = options.border or "1px solid white" |
} |
} |
if options.horizontalAlignment == "right" then |
if options.horizontalAlignment == "right" then |
overlayStyle.right = options.horizontalOffset .. "px" |
overlayStyle.right = options.horizontalOffset .. "px" |
else |
else |
overlayStyle.left = options.horizontalOffset .. "px" |
overlayStyle.left = options.horizontalOffset .. "px" |
end |
end |
if options.verticalAlignment == "bottom" then |
if options.verticalAlignment == "bottom" then |
overlayStyle.bottom = options.verticalOffset .. "px" |
overlayStyle.bottom = options.verticalOffset .. "px" |
else |
else |
overlayStyle.top = options.verticalOffset .. "px" |
overlayStyle.top = options.verticalOffset .. "px" |
end |
end |
local overlayDiv = mw.html.create("div") |
local overlayDiv = mw.html.create("div") |
:css(overlayStyle) |
:css(overlayStyle) |
:wikitext(overlayMap) |
:wikitext(overlayMap) |
container |
container |
:node(overlayDiv) |
:node(overlayDiv) |
:wikitext(baseMap) |
:wikitext(baseMap) |
if not options.isThumbnail then |
if not options.isThumbnail then |
return tostring(container) |
return tostring(container) |
end |
end |
local classlist = container:getAttr("class") |
local classlist = container:getAttr("class") |
classlist = mw.ustring.gsub(classlist, "%a*"..options.align, "") |
classlist = mw.ustring.gsub(classlist, "%a*"..options.align, "") |
container:attr("class", classlist) |
container:attr("class", classlist) |
local outerCountainer = mw.html.create("div") |
local outerCountainer = mw.html.create("div") |
:addClass("mapframe-withOverlay-outerContainer") |
:addClass("mapframe-withOverlay-outerContainer") |
:addClass("mw-kartographer-container") |
:addClass("mw-kartographer-container") |
:addClass("thumb") |
:addClass("thumb") |
if options.align == "left" or options.align == "right" then |
if options.align == "left" or options.align == "right" then |
outerCountainer:addClass("t"..options.align) |
outerCountainer:addClass("t"..options.align) |
else -- alignment is "center" |
else -- alignment is "center" |
outerCountainer |
outerCountainer |
:addClass("tnone") |
:addClass("tnone") |
:addClass("center") |
:addClass("center") |
end |
end |
outerCountainer |
outerCountainer |
:tag("div") |
:tag("div") |
:addClass("thumbinner") |
:addClass("thumbinner") |
:css("width", options.width.."px") |
:css("width", options.width.."px") |
:node(container) |
:node(container) |
:node(options.caption and mw.html.create("div") |
:node(options.caption and mw.html.create("div") |
:addClass("thumbcaption") |
:addClass("thumbcaption") |
:wikitext(options.caption) |
:wikitext(options.caption) |
) |
) |
return tostring(outerCountainer) |
return tostring(outerCountainer) |
end |
end |
--[[---------------------------------------------------------------------------- |
--[[---------------------------------------------------------------------------- |
Package to be exported, i.e. methods which will available to templates and |
Package to be exported, i.e. methods which will available to templates and |
other modules. |
other modules. |
----------------------------------------------------------------------------]]-- |
----------------------------------------------------------------------------]]-- |
local p = {} |
local p = {} |
-- Entry point for templates |
-- Entry point for templates |
function p.main(frame) |
function p.main(frame) |
local parent = frame.getParent(frame) |
local parent = frame.getParent(frame) |
-- Check for overlay option |
-- Check for overlay option |
local overlay = util.getParameterValue(parent.args, 'overlay') |
local overlay = util.getParameterValue(parent.args, 'overlay') |
local hasOverlay = overlay and mw.text.trim(overlay) ~= "" |
local hasOverlay = overlay and mw.text.trim(overlay) ~= "" |
-- Check for switch option |
-- Check for switch option |
local switch = util.getParameterValue(parent.args, 'switch') |
local switch = util.getParameterValue(parent.args, 'switch') |
local isMulti = switch and mw.text.trim(switch) ~= "" |
local isMulti = switch and mw.text.trim(switch) ~= "" |
-- Create output by choosing method to suit options |
-- Create output by choosing method to suit options |
local output |
local output |
if hasOverlay then |
if hasOverlay then |
output = p.withOverlay(parent.args) |
output = p.withOverlay(parent.args) |
elseif isMulti then |
elseif isMulti then |
output = p.multi(parent.args) |
output = p.multi(parent.args) |
else |
else |
output = p._main(parent.args) |
output = p._main(parent.args) |
end |
end |
-- Preprocess output before returning it |
-- Preprocess output before returning it |
return frame:preprocess(output) |
return frame:preprocess(output) |
end |
end |
-- Entry points for modules |
-- Entry points for modules |
function p._main(_args) |
function p._main(_args) |
local args = util.trimArgs(_args) |
local args = util.trimArgs(_args) |
local tagContent = make.content(args) |
local tagContent = make.content(args) |
local display = mw.text.split(util.getParameterValue(args, 'display') or L10n.defaults.display, '%s*' .. L10n.str.dsep .. '%s*') |
local display = mw.text.split(util.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 |
local output |
local output |
if displayInTitle and displayInline then |
if displayInTitle and displayInline then |
output = make.titleOutput(args, tagContent) .. make.inlineOutput(args, tagContent) |
output = make.titleOutput(args, tagContent) .. make.inlineOutput(args, tagContent) |
elseif displayInTitle then |
elseif displayInTitle then |
output = make.titleOutput(args, tagContent) |
output = make.titleOutput(args, tagContent) |
elseif displayInline then |
elseif displayInline then |
output = make.inlineOutput(args, tagContent) |
output = make.inlineOutput(args, tagContent) |
else |
else |
error(L10n.error.badDisplayPara) |
error(L10n.error.badDisplayPara) |
end |
end |
return output |
return output |
end |
end |
function p.multi(_args) |
function p.multi(_args) |
local args = util.trimArgs(_args) |
local args = util.trimArgs(_args) |
if not args[L10n.para.switch] then error(L10n.error.noSwitchPara, 0) end |
if not args[L10n.para.switch] then error(L10n.error.noSwitchPara, 0) end |
local switchParamValue = util.getParameterValue(args, 'switch') |
local switchParamValue = util.getParameterValue(args, 'switch') |
local switchLabels = util.tableFromList(switchParamValue) |
local switchLabels = util.tableFromList(switchParamValue) |
if #switchLabels == 1 then error(L10n.error.oneSwitchLabel, 0) end |
if #switchLabels == 1 then error(L10n.error.oneSwitchLabel, 0) end |
local mapframeArgs = {} |
local mapframeArgs = {} |
local switchParams = {} |
local switchParams = {} |
for name, val in pairs(args) do |
for name, val in pairs(args) do |
-- Copy to mapframeArgs, if not the switch labels or a switch parameter |
-- Copy to mapframeArgs, if not the switch labels or a switch parameter |
if val ~= switchParamValue and not string.match(val, "^"..L10n.str.switch..":") then |
if val ~= switchParamValue and not string.match(val, "^"..L10n.str.switch..":") then |
mapframeArgs[name] = val |
mapframeArgs[name] = val |
end |
end |
-- Check if this is a param to switch. If so, store the name and switch |
-- Check if this is a param to switch. If so, store the name and switch |
-- values in switchParams table. |
-- values in switchParams table. |
local switchList = string.match(val, "^"..L10n.str.switch..":(.+)") |
local switchList = string.match(val, "^"..L10n.str.switch..":(.+)") |
if switchList ~= nil then |
if switchList ~= nil then |
local values = util.tableFromList(switchList) |
local values = util.tableFromList(switchList) |
if #values == 1 then |
if #values == 1 then |
error(string.format(L10n.error.oneSwitchValue, name), 0) |
error(string.format(L10n.error.oneSwitchValue, name), 0) |
end |
end |
switchParams[name] = values |
switchParams[name] = values |
end |
end |
end |
end |
if util.tableCount(switchParams) == 0 then |
if util.tableCount(switchParams) == 0 then |
error(L10n.error.noSwitchLists, 0) |
error(L10n.error.noSwitchLists, 0) |
end |
end |
local switchCount = util.subTablesCount(switchParams) |
local switchCount = util.subTablesCount(switchParams) |
if not switchCount then |
if not switchCount then |
error(L10n.error.switchMismatches, 0) |
error(L10n.error.switchMismatches, 0) |
elseif switchCount > #switchLabels then |
elseif switchCount > #switchLabels then |
error(string.format(L10n.error.fewerSwitchLabels, switchCount, #switchLabels), 0) |
error(string.format(L10n.error.fewerSwitchLabels, switchCount, #switchLabels), 0) |
end |
end |
-- Ensure a plain frame will be used (thumbnail will be built by the |
-- Ensure a plain frame will be used (thumbnail will be built by the |
-- make.switcherHtml function if required, so that switcher options are |
-- make.switcherHtml function if required, so that switcher options are |
-- inside the thumnail) |
-- inside the thumnail) |
mapframeArgs.plain = "yes" |
mapframeArgs.plain = "yes" |
local switcher = {} |
local switcher = {} |
for i = 1, switchCount do |
for i = 1, switchCount do |
local label = switchLabels[i] |
local label = switchLabels[i] |
for name, values in pairs(switchParams) do |
for name, values in pairs(switchParams) do |
mapframeArgs[name] = values[i] |
mapframeArgs[name] = values[i] |
end |
end |
table.insert(switcher, { |
table.insert(switcher, { |
map = p._main(mapframeArgs), |
map = p._main(mapframeArgs), |
label = "Show "..label |
label = "Show "..label |
}) |
}) |
end |
end |
return make.switcherHtml(switcher, { |
return make.switcherHtml(switcher, { |
alignment = args["frame-align"] or "right", |
alignment = args["frame-align"] or "right", |
isThumbnail = (args.frame and not args.plain) and true or false, |
isThumbnail = (args.frame and not args.plain) and true or false, |
width = args["frame-width"] or L10n.defaults.frameWidth, |
width = args["frame-width"] or L10n.defaults.frameWidth, |
caption = args.text |
caption = args.text |
}) |
}) |
end |
end |
function p.withOverlay(_args) |
function p.withOverlay(_args) |
-- Get and trim wikitext for overlay map |
-- Get and trim wikitext for overlay map |
local overlayMap = _args.overlay |
local overlayMap = _args.overlay |
if type(overlayMap) == 'string' then |
if type(overlayMap) == 'string' then |
overlayMap = overlayMap:match('^%s*(.-)%s*$') |
overlayMap = overlayMap:match('^%s*(.-)%s*$') |
end |
end |
local isThumbnail = (util.getParameterValue(_args, "frame") and not util.getParameterValue(_args, "plain")) and true or false |
local isThumbnail = (util.getParameterValue(_args, "frame") and not util.getParameterValue(_args, "plain")) and true or false |
-- Get base map using the _main function, as a plain map |
-- Get base map using the _main function, as a plain map |
local args = util.trimArgs(_args) |
local args = util.trimArgs(_args) |
args.plain = "yes" |
args.plain = "yes" |
local basemap = p._main(args) |
local basemap = p._main(args) |
-- Extract overlay options from args |
-- Extract overlay options from args |
local overlayOptions = { |
local overlayOptions = { |
width = util.getParameterValue(args, "frameWidth") or L10n.defaults.frameWidth, |
width = util.getParameterValue(args, "frameWidth") or L10n.defaults.frameWidth, |
height = util.getParameterValue(args, "frameHeight") or L10n.defaults.frameHeight, |
height = util.getParameterValue(args, "frameHeight") or L10n.defaults.frameHeight, |
align = util.getParameterValue(args, "frameAlign") or L10n.defaults.frameAlign, |
align = util.getParameterValue(args, "frameAlign") or L10n.defaults.frameAlign, |
border = util.getParameterValue(args, "overlayBorder") or L10n.defaults.overlayBorder, |
border = util.getParameterValue(args, "overlayBorder") or L10n.defaults.overlayBorder, |
horizontalAlignment = util.getParameterValue(args, "overlayHorizontalAlignment") or L10n.defaults.overlayHorizontalAlignment, |
horizontalAlignment = util.getParameterValue(args, "overlayHorizontalAlignment") or L10n.defaults.overlayHorizontalAlignment, |
horizontalOffset = util.getParameterValue(args, "overlayHorizontalOffset") or L10n.defaults.overlayHorizontalOffset, |
horizontalOffset = util.getParameterValue(args, "overlayHorizontalOffset") or L10n.defaults.overlayHorizontalOffset, |
verticalAlignment = util.getParameterValue(args, "overlayVerticalAlignment") or L10n.defaults.overlayVerticalAlignment, |
verticalAlignment = util.getParameterValue(args, "overlayVerticalAlignment") or L10n.defaults.overlayVerticalAlignment, |
verticalOffset = util.getParameterValue(args, "overlayVerticalOffset") or L10n.defaults.overlayVerticalOffset, |
verticalOffset = util.getParameterValue(args, "overlayVerticalOffset") or L10n.defaults.overlayVerticalOffset, |
isThumbnail = isThumbnail, |
isThumbnail = isThumbnail, |
caption = util.getParameterValue(args, "text") or L10n.defaults.text |
caption = util.getParameterValue(args, "text") or L10n.defaults.text |
} |
} |
-- Make the HTML for the overlaying maps |
-- Make the HTML for the overlaying maps |
return make.overlayHtml(overlayMap, basemap, overlayOptions) |
return make.overlayHtml(overlayMap, basemap, overlayOptions) |
end |
end |
return p |
return p |