Module:Road data/sandbox
Appearance
This is the module sandbox page for Module:Road data (diff). See also the companion subpage for test cases (run). |
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 18,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. |
Usage
[edit]{{#invoke:Road data|function_name}}
Submodules
[edit]Submodules of Module:Road data are used to process and display the road data stored in the modules listed at #Data modules. There are also a few that contain additional data.
Data modules
[edit]String modules
[edit]String modules are used to store type data for use with several road templates, including {{jct}} and {{routelist row}}.
Banner modules
[edit]Banner modules store data about banners that should be shown. For example, Module:Road data/banners/USA defines the "TO" banner shown when {{jct}} is used with a |to=
parameter in the United States i.e.
To I-82.
Mask modules
[edit]Mask modules store masks that can be hooked into by #String modules. See Module:Road data/strings#Hooks and Module:Road data/parser/hooks#mask.
local p = {}
local concat = table.concat
local insert = table.insert
local format = mw.ustring.format
local trim = mw.text.trim
local parserModule = require("Module:Road data/parser")
local parser = parserModule.parser
local util = require("Module:Road data/util")
local sizeModuleName = 'Module:Road data/size/sandbox' -- REMOVE SANDBOX
-- Shields
local function addContextBanner(route, name, suffix, bannerSpec, size)
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
-- Add banner plate
insert(bannerSpec, {shield, size})
end
end
local function bannerSpec(banner, bannerSize, bannerSuffix, route, size)
local banners = {}
if type(banner) == "table" then
local bannerSizeIsNotTable = type(bannerSize) ~= "table"
for i, filename in ipairs(banner) do
local singleBannerSize = bannerSizeIsNotTable and bannerSize or bannerSize[i]
insert(banners, {filename, singleBannerSize})
end
elseif banner ~= '' then
insert(banners, {banner, bannerSize})
end
if route.dir then
addContextBanner(route, 'dir', bannerSuffix, banners, size)
end
if route.to then
addContextBanner(route, 'to', bannerSuffix, banners, size)
end
return banners
end
local function shieldSpec(route, shieldType, size, ignoreUpright)
local shieldSpec = {}
local shield
if route.to and shieldType == 'main' then shield = parser(route, 'shieldtomain') end
if not shield and route.to then shield = parser(route, 'shieldto') end
if not shield and shieldType == 'main' then shield = parser(route, 'shieldmain') end
if not shield and shieldType == 'list' then shield = parser(route, 'shieldlist') end
if not shield then shield = parser(route, 'shield') or '' end
if shield == '' then return shieldSpec end
local orientation = parser(route, 'orientation')
local shieldSize
local shieldSizeIsNotTable
if type(orientation) == "table" then
shieldSize = {}
shieldSizeIsNotTable = false
for i, shieldOrientation in ipairs(orientation) do
insert(shieldSize, (shieldOrientation ~= 'upright' or ignoreUpright) and 'x' .. size or size)
end
else
shieldSize = (orientation ~= 'upright' or ignoreUpright) and 'x' .. size or size
shieldSizeIsNotTable = true
end
local banner = parser(route, 'banner') or {}
local bannerSize = size
local bannerSuffix = parser(route, 'bannersuffix')
local bannerIsNotTable = type(banner) ~= "table"
local bannerSuffixIsNotTable = type(bannerSuffix) ~= "table"
if type(shield) == "table" then
for i, filename in ipairs(shield) do
-- Fallback to default size for the size style
local singleShieldSize = shieldSizeIsNotTable and shieldSize or shieldSize[i] or size
-- banner.all describes banners that apply to all multiple shields
local shieldBanner = bannerIsNotTable and banner or (banner[i] or banner.all or {})
local shieldBannerSuffix = bannerSuffix and (bannerSuffixIsNotTable and bannerSuffix or bannerSuffix[i])
insert(shieldSpec, {
shield = {filename, singleShieldSize},
banners = bannerSpec(shieldBanner, bannerSize, shieldBannerSuffix, route, size),
route = route
})
end
elseif shield ~= '' then
insert(shieldSpec, {
shield = {shield, shieldSize},
banners = bannerSpec(banner, bannerSize, bannerSuffix, route, size),
route = route
})
end
return shieldSpec
end
local missingShields
local shieldExistsCache = {}
local function shieldExists(shield)
local exists = shieldExistsCache[shield]
if exists == nil then
local file = mw.title.new(shield, 'Media').file
exists = file.exists
-- Cache result
shieldExistsCache[shield] = exists
end
if exists then return true end
insert(missingShields, shield)
return false
end
local function render(shieldEntry, nonDecorative)
local shield = shieldEntry.shield
local banners = shieldEntry.banners
local exists = shieldExists(shield[1])
if not exists then return '' end
local alt = ''
if nonDecorative then
alt = (parser(shieldEntry.route, 'abbr') or '') .. ' marker'
end
local shieldCode = format("[[File:%s|%s|link=|alt=%s]]", shield[1], shield[2], alt)
if not banners[1] then return shieldCode end
for _, banner in ipairs(banners) do
shieldCode = format(
"[[File:%s|%s|link=|alt=%s]]<br>%s",
banner[1],
banner[2],
alt,
shieldCode
)
end
return '<span style="display: inline-block; vertical-align: baseline; line-height: 0; text-align: center;">'
.. shieldCode
.. '</span>'
end
function p.shield(route, shieldType, sizeOrStyle, nonDecorative)
missingShields = {}
local size
local ignoreUpright
if sizeOrStyle and sizeOrStyle:match('^%d+px$') then
size = sizeOrStyle
ignoreUpright = false
else
local sizeModule = require(sizeModuleName) -- REMOVE SANDBOX
size = sizeModule._size({ style = sizeOrStyle })
ignoreUpright = sizeModule._ignoreUpright(sizeOrStyle)
end
local rendered = {}
for _, entry in ipairs(shieldSpec(route, shieldType, size, ignoreUpright)) do
insert(rendered, render(entry, nonDecorative))
end
return concat(rendered, ' '), missingShields
end
-- Links
function p.link(route, useName)
local abbr, errMsg = parser(route, useName and 'name' or '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
return p