Module:Road data
Appearance
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | 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
{{#invoke:Road data|function_name}}
Submodules
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
String modules
String modules are used to store type data for use with several road templates, including {{jct}} and {{routelist row}}.
Banner modules
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
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 = {}
-- Change to main module upon deployment
local parserModule = require "Module:Road data/parser/sandbox"
local concat = table.concat
local insert = table.insert
local format = mw.ustring.format
-- Import module function to work with passed arguments
local getArgs = require('Module:Arguments').getArgs
local parser = parserModule.parser
-- Shields
local defaultShieldSize = "20"
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', bannerModule, name)
if shield and shield ~= '' then
if suffix == nil then
suffix = parser(route, 'shield', bannerModule, 'suffix')
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)
end
end
local function bannerSpec(banner, bannerSuffix, route)
local banners = {}
if type(banner) == "table" then
banners = banner
elseif banner ~= '' then
insert(banners, banner)
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)
local shieldSpec = {}
local shield = parser(route, 'shield') or ''
if shield == '' then return shieldSpec end
local banner = parser(route, 'banner') or {}
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
-- 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,
banners = bannerSpec(shieldBanner, shieldBannerSuffix, route)
})
end
elseif shield ~= '' then
insert(shieldSpec, {
shield = shield,
banners = bannerSpec(banner, 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, minShieldSize)
local shield = shieldEntry.shield
local banners = shieldEntry.banners
local exists, landscape = shieldExists(shield)
if not exists then return '' end
local shieldCode = format("[[File:%s|%s%spx|link=|%s]]", shield, landscape and "x" or "", minShieldSize, shield)
if not banners[1] then
return shieldCode
end
for _,banner in ipairs(banners) do
if shieldExists(banner) then
shieldCode = format("[[File:%s|%spx|link=|%s]]<br>%s", banner, minShieldSize, banner, 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, minShieldSize)
missingShields = {}
minShieldSize = minShieldSize or defaultShieldSize
if route.rdt then
minShieldSize = mw.ustring.match(route.rdt, '(%d+)') or "17"
end
local rendered = {}
for _,entry in ipairs(shieldSpec(route)) do
insert(rendered, render(entry, minShieldSize))
end
return concat(rendered), missingShields
end
return p