Module:Road data/locations: Difference between revisions
Appearance
Content deleted Content added
adj |
BrandonXLF (talk | contribs) Keep shield and link functions at Module:Road data |
||
Line 1: | Line 1: | ||
local p = {} |
local p = {} |
||
local parserModule = require("Module:Road data/parser") |
|||
-- Change to "" upon deployment. |
|||
local |
local util = require("Module:Road data/util") |
||
local parserModuleName = "Module:Road data/parser" .. moduleSuffix |
|||
local statenameModuleName = "Module:Jct/statename" .. moduleSuffix -- TODO transition |
|||
local concat = table.concat |
|||
local insert = table.insert |
|||
local format = mw.ustring.format |
local format = mw.ustring.format |
||
local trim = mw.text.trim |
local trim = mw.text.trim |
||
local parserModule = require(parserModuleName) |
|||
local parser = parserModule.parser |
local parser = parserModule.parser |
||
local util = require("Module:Road data/util") |
|||
local sizeModule = require("Module:Road data/size").size({style = "test"}) |
|||
-- Shields |
|||
local defaultShieldSize = 30 |
|||
local function addContextBanner(route, name, suffix, bannerSpec) |
|||
local bannerModule = 'Module:Road data/banners/' .. string.upper(route.country) |
|||
local shieldfield = name .. 'shield' |
|||
local shield = parser(route, shieldfield) |
|||
if shield == nil then |
|||
-- This route type does not define shield. |
|||
-- Find shield in the default banner table. |
|||
shield = parser(route, 'shield', name, bannerModule) |
|||
if shield and shield ~= '' then |
|||
if suffix == nil then |
|||
suffix = parser(route, 'shield', 'suffix', bannerModule) |
|||
end |
|||
if suffix and suffix ~= '' then |
|||
shield = shield .. " " .. suffix |
|||
end |
|||
shield = shield .. ".svg" |
|||
end |
|||
end |
|||
if shield and shield ~= '' then |
|||
local shieldSize = sizeModule |
|||
-- Add banner plate. |
|||
insert(bannerSpec, {shield, shieldSize}) |
|||
end |
|||
end |
|||
local function bannerSpec(banner, bannerSize, bannerSuffix, route) |
|||
local banners = {} |
|||
if type(banner) == "table" then |
|||
local bannerSizeIsNotTable = type(bannerSize) ~= "table" |
|||
for i,filename in ipairs(banner) do |
|||
local bannersize = bannerSizeIsNotTable and bannerSize or bannerSize[i] or defaultShieldSize |
|||
insert(banners, {filename, bannersize}) |
|||
end |
|||
elseif banner ~= '' then |
|||
insert(banners, {banner, bannerSize}) |
|||
end |
|||
if route.dir then |
|||
addContextBanner(route, 'dir', bannerSuffix, banners) |
|||
end |
|||
if route.to then |
|||
addContextBanner(route, 'to', bannerSuffix, banners) |
|||
end |
|||
return banners |
|||
end |
|||
local function shieldSpec(route, mainShield) |
|||
local shieldSpec = {} |
|||
local shield |
|||
if mainShield then shield = parser(route, "shieldmain") end |
|||
if not shield then shield = parser(route, 'shield') or '' end |
|||
if shield == '' then return shieldSpec end |
|||
local orientation = parser(route, 'orientation') |
|||
local function size(route) |
|||
if orientation == "upright" then |
|||
return sizeModule |
|||
else return "x" .. sizeModule |
|||
end |
|||
end |
|||
local shieldsize = size(route) |
|||
local banner = parser(route, 'banner') or {} |
|||
local bannersize = sizeModule |
|||
local bannersuffix = parser(route, 'bannersuffix') |
|||
local bannerIsNotTable = type(banner) ~= "table" |
|||
local bannersizeIsNotTable = type(bannersize) ~= "table" |
|||
local bannersuffixIsNotTable = type(bannersuffix) ~= "table" |
|||
if type(shield) == "table" then |
|||
for i,filename in ipairs(shield) do |
|||
local size = shieldsize or shieldsize[i] |
|||
if size == "" then size = nil end |
|||
-- banner.all describes banners that apply to all multiple shields. |
|||
local shieldBanner = bannerIsNotTable and banner or (banner[i] or banner.all or {}) |
|||
-- Banner size is default if the corresponding entry |
|||
-- in bannerSize table is not set. |
|||
local shieldBannerSize = |
|||
bannersizeIsNotTable and bannersize |
|||
or (bannersize[i] or bannersize.all or defaultShieldSize) |
|||
local shieldBannerSuffix = bannersuffix and (bannersuffixIsNotTable and bannersuffix or bannersuffix[i]) |
|||
insert(shieldSpec, { |
|||
shield = {filename, size}, |
|||
banners = bannerSpec(shieldBanner, shieldBannerSize, shieldBannerSuffix, route) |
|||
}) |
|||
end |
|||
elseif shield ~= '' then |
|||
if shieldsize == "" then shieldsize = nil end |
|||
insert(shieldSpec, { |
|||
shield = {shield, shieldsize}, |
|||
banners = bannerSpec(banner, bannersize, bannersuffix, route) |
|||
}) |
|||
end |
|||
return shieldSpec |
|||
end |
|||
local missingShields |
|||
local shieldExistsCache = {} |
|||
-- Return up to two booleans. |
|||
-- The first boolean is false if `shield` does not exist, and true otherwise. |
|||
-- If the first boolean is true, the second boolean is true if the shield is |
|||
-- landscape (width >= height), and false otherwise. |
|||
local function shieldExists(shield) |
|||
local result = shieldExistsCache[shield] |
|||
if result == nil then |
|||
local file = mw.title.new(shield, 'Media').file |
|||
-- Cache result. |
|||
local exists = file.exists |
|||
result = {exists} |
|||
if exists then result[2] = file.width >= file.height end |
|||
shieldExistsCache[shield] = result |
|||
end |
|||
if result[1] then return true, result[2] end |
|||
insert(missingShields, shield) |
|||
return false |
|||
end |
|||
local function render(shieldEntry, scale, showLink) |
|||
local shield = shieldEntry.shield |
|||
local banners = shieldEntry.banners |
|||
local exists, landscape = shieldExists(shield[1]) |
|||
if not exists then return '' end |
|||
local size |
|||
if shield[2] then |
|||
local width, height = mw.ustring.match(shield[2], "(%d*)x?(%d*)") |
|||
width = tonumber(width) |
|||
height = tonumber(height) |
|||
local sizeparts = {} |
|||
if width then |
|||
insert(sizeparts, format("%d", width * scale)) |
|||
end |
|||
if height then |
|||
insert(sizeparts, format("x%d", height * scale)) |
|||
end |
|||
size = concat(sizeparts) |
|||
else |
|||
size = format("%s%d", landscape and "x" or "", defaultShieldSize * scale) |
|||
end |
|||
local shieldCode = format("[[File:%s|%spx|link=|alt=]]", shield[1], size) |
|||
if not banners[1] then return shieldCode end |
|||
for _,banner in ipairs(banners) do |
|||
if shieldExists(banner[1]) then |
|||
shieldCode = format("[[File:%s|%spx|link=|alt=]]<br>%s", |
|||
banner[1], |
|||
banner[2], |
|||
shieldCode) |
|||
end |
|||
end |
|||
return '<span style="display: inline-block; vertical-align: baseline; line-height: 0; text-align: center;">' .. shieldCode .. '</span>' |
|||
end |
|||
function p.shield(route, scale, showLink, mainShield) |
|||
missingShields = {} |
|||
if route.rdt then |
|||
local shieldSize = mw.ustring.match(route.rdt, '^(%d+)$') or 17 |
|||
scale = shieldSize/defaultShieldSize |
|||
end |
|||
scale = scale or 1 |
|||
local rendered = {} |
|||
for _,entry in ipairs(shieldSpec(route, mainShield)) do |
|||
insert(rendered, render(entry, scale, showLink)) |
|||
end |
|||
return concat(rendered), missingShields |
|||
end |
|||
function p.link(route) |
|||
local abbr, errMsg = parser(route, 'abbr') |
|||
if not abbr then |
|||
route.typeerror = true |
|||
return util.err(errMsg or format("Invalid type: %s", route.type or "(nil)")) |
|||
end |
|||
if route.nolink then return abbr, abbr end |
|||
local link = parser(route, 'link') or '' |
|||
if link == '' then return abbr, abbr end |
|||
return format("[[%s|%s]]", link, abbr), abbr |
|||
end |
|||
local function stateName(args) |
local function stateName(args) |
||
-- TODO transition |
-- TODO transition |
||
local data = mw.loadData( |
local data = mw.loadData("Module:Jct/statename") |
||
local abbr = args.state or args.province |
local abbr = args.state or args.province |
||
local countryData = data[args.country] |
local countryData = data[args.country] |
Revision as of 20:10, 23 August 2024
![]() | This module is rated as beta, and is ready for widespread use. It is still new and should be used with some caution to ensure the results are as expected. |
![]() | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
![]() | This Lua module is used on approximately 12,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
This modules returns table with the correct location links using the common
fields of the Module:Road data/strings modules. See Module:Road data/locations/testcases for example outputs.
local p = {}
local parserModule = require("Module:Road data/parser")
local util = require("Module:Road data/util")
local format = mw.ustring.format
local trim = mw.text.trim
local parser = parserModule.parser
local function stateName(args)
-- TODO transition
local data = mw.loadData("Module:Jct/statename")
local abbr = args.state or args.province
local countryData = data[args.country]
return countryData and countryData[abbr]
end
function p.locations(args, module, group)
module = module or ""
local modulearticle = module .. "article"
local moduleprefix = module .. "prefix"
local modulenameprefix = module .. "nameprefix"
local modulenamesuffix = module .. "namesuffix"
local warnings = {}
-- Region, for disambiguation
local region = parserModule.parser(args, "region", " common ")
if not region then
-- TODO transition
if args.region then
warnings.region = "region parameter is deprecated"
region = args.region
elseif args.country and (args.state or args.province) then
warnings.region = "Inferring region from country and state/province"
region = stateName(args)
end
end
local regionName
local regionText
if type(region) == "table" then
regionName = region.name
regionText = format("[[%s|%s]]", region.link, regionName)
elseif region then
regionName = region
regionText = format("[[%s]]", regionName)
end
args.region = regionName
local locations = parserModule.parser(args, "locations", " common ") or {}
-- Primary topic requires no specialization to supplied locations.
local primaryTopic = not locations and module == "jctint" and args.primary_topic ~= 'no'
if args.primary_topic then
-- TODO transition
warnings.primary_topic = "primary_topic parameter is deprecated"
end
-- Independent city
local indepCityText
if args.indep_city_special then
indepCityText = args.indep_city_special -- Overrides `indep_city` argument.
elseif args.indep_city then
local indepCity = args.indep_city
local spec = locations.indep_city
if spec then
local link = format("%s%s%s",
spec.linkprefix or "", indepCity, spec.linksuffix or "")
local name = format("%s%s%s",
spec[modulenameprefix] or spec.nameprefix or "",
indepCity,
spec[modulenamesuffix] or spec.namesuffix or "")
indepCityText = format("%s%s[[%s|%s]]",
spec[modulearticle] or spec.article or "",
spec[moduleprefix] or spec.prefix or "",
link, name)
else
-- TODO transition
warnings.indep_city = "Spec for indep_city parameter undefined in road data module"
local cityLink -- Wikilink for independent city
if primaryTopic then
cityLink = format('[[%s]]', indepCity)
else
-- Specialize independent city to the region.
cityLink = format('[[%s, %s|%s]]', indepCity, region, indepCity)
end
indepCityText = "[[Independent city|City]] of " .. cityLink
end
end
if indepCityText then
return {region = regionText, indep_city = indepCityText, warnings = warnings}
end
-- First-level subdivision, e.g., county
-- Name of the type of subdivision, e.g., "County" and "Parish"
local sub1name = args.sub1name -- TODO transition
local sub1Text
if args.sub1_special then
sub1Text = args.sub1_special -- Overrides `sub1` argument.
elseif args.sub1 then
local sub1 = args.sub1
local article
local link = sub1
local name = sub1
-- Type of first-level subdivision area, as a form of disambiguation
local sub1area = args.sub1area
if sub1area then
local sub1areaSpec = locations.sub1areas and locations.sub1areas[sub1area]
if sub1areaSpec then
article = sub1areaSpec[modulearticle] or sub1areaSpec.article or ""
link = format("%s%s%s",
sub1areaSpec.linkprefix or "", link, sub1areaSpec.linksuffix or "")
name = format("%s%s%s",
group and "" or sub1areaSpec[modulenameprefix] or sub1areaSpec.nameprefix or "",
name,
group and "" or sub1areaSpec[modulenamesuffix] or sub1areaSpec.namesuffix or "")
else
-- TODO report error
local errMsg = util.err(format("Undefined sub1area: %s", sub1area))
name = format("%s%s", name, errMsg)
end
end
if locations.sub1 then
local spec = locations.sub1
-- Prepend and append text from spec.
link = format("%s%s%s",
spec.linkprefix or "", link, spec.linksuffix or "")
name = format("%s%s%s",
spec[modulenameprefix] or spec.nameprefix or "",
name,
spec[modulenamesuffix] or spec.namesuffix or "")
sub1Text = format("%s[[%s|%s]]", article or "", link, name)
else
-- TODO transition
warnings.sub1 = "Spec for sub1 parameter undefined in road data module"
-- Add type (if specified) to wikilink for first-level subdivision.
local sub1Link = sub1name and trim(format("%s %s", sub1, sub1name)) or sub1
local sub1Name = module == "jcttop" and sub1Link or sub1
if primaryTopic then
sub1Text = format('[[%s|%s]]', sub1Link, sub1Name)
else
-- Specialize first-level subdivision, with type added, to the region.
sub1Text = format('[[%s, %s|%s]]', sub1Link, region, sub1Name)
end
end
end
-- Second-level subdivision, e.g., city and town
local sub2Text
if args.sub2_special then
sub2Text = args.sub2_special -- Overrides `sub2` argument.
elseif args.sub2 then
local sub2 = args.sub2
if sub2 == "none" then
sub2Text = "​" -- Zero-width space
elseif sub2 == " " then
-- TODO transition
warnings.sub2 = " argument for sub2 parameter is deprecated"
sub2Text = "​" -- Zero-width space
elseif primaryTopic then
-- TODO transition
sub2Text = format("[[%s]]", sub2)
else
local article
local link = sub2
local name = sub2
-- Type of area, e.g., city and village, as a form of disambiguation
local sub2area = args.sub2area --[[TODO transition]] or args.area
if sub2area then
local sub2areaSpec = locations.sub2areas and locations.sub2areas[sub2area]
if not sub2areaSpec then
-- TODO transition
warnings.sub2 =
format("Spec for area parameter '%s' undefined in road data module", sub2area)
local sub2areas = { -- table of different area types
city = {
linksuffix = " (city)",
jcttoparticle = "the ",
nameprefix = "City of "
},
town = {
linksuffix = " (town)",
jcttoparticle = "the ",
nameprefix = "Town of "
},
village = {
linksuffix = " (village)",
jcttoparticle = "the ",
nameprefix = "Village of "
},
community = {
linksuffix = " (community)",
jcttoparticle = "the ",
nameprefix = "Community of "
},
CDP = {
linksuffix = " (CDP)",
jcttoparticle = "the ",
nameprefix = "Community of "
},
hamlet = {
linksuffix = " (hamlet)",
jcttoparticle = "the ",
nameprefix = "Hamlet of "
},
["unorganized territory"] = {
linksuffix = " (unorganized territory)",
jcttoparticle = "the ",
nameprefix = "Unorganized Territory of "
},
township = {
linksuffix = " Township",
namesuffix = " Township",
}
}
sub2areaSpec = sub2areas[sub2area]
end
if sub2areaSpec then
article = sub2areaSpec[modulearticle] or sub2areaSpec.article or ""
link = format("%s%s%s",
sub2areaSpec.linkprefix or "", link, sub2areaSpec.linksuffix or "")
name = format("%s%s%s",
group and "" or sub2areaSpec[modulenameprefix] or sub2areaSpec.nameprefix or "",
name,
group and "" or sub2areaSpec[modulenamesuffix] or sub2areaSpec.namesuffix or "")
else
-- TODO report error
local errMsg = util.err(format("Undefined sub2area: %s", sub2area))
name = format("%s%s", name, errMsg)
end
end
if locations.sub2 then
local spec = locations.sub2
-- Prepend and append text from spec.
link = format("%s%s%s",
spec.linkprefix or "", link, spec.linksuffix or "")
name = format("%s%s%s",
spec[modulenameprefix] or spec.nameprefix or "",
name,
spec[modulenamesuffix] or spec.namesuffix or "")
else
-- TODO transition
warnings.sub2 = "Spec for sub2 parameter undefined in road data module"
-- Some second-level subdivisions are not unique in a given region.
-- `sub1dab` is the first-level subdivision to be used for disambiguation.
local sub1dab = args.sub1dab
if sub1dab then
sub1dab = sub1name and trim(format("%s %s", sub1dab, sub1name)) or sub1dab
link = format("%s, %s", link, sub1dab)
end
link = format("%s, %s", link, region) -- Add region to wikilink
end
sub2Text = format("%s[[%s|%s]]", article or "", link, name)
end
end
return {region = regionText, sub1 = sub1Text, sub2 = sub2Text, warnings = warnings}
end
return p