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 24,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 module depends on the following other modules: |
This module uses TemplateStyles: |
This module implements the {{Track gauge}} template. Please see the template page for documentation on how to use the main TrackGauge function.
Gauge data
The gauge information is stored at Module:Track gauge/data; to add new gauges, see the instructions there.
Data checks
This module includes a function that checks the data page for errors. It is used with the following code:
{{#invoke:Track gauge/autodocument|checkData|name of data page}}
The first positional parameter is the name of the data page that you want to be checked. If this is omitted, the module checks Module:Track gauge/data.
Tracking category
Module set
- Module:Track gauge
- Module:Track gauge/data
- Module:Track gauge/autodocument (track gauges list)
-- This module implements the {{Track gauge}} template.
-- Data is in Module:Track gauge/data
local p = {}
local gaugeDataAll = nil
local dataPageName = 'Module:Track gauge/data' -- set /data/sandbox here to test data/sandbox
-----------------------------------------------------------------------------------
-- prepareArgs -- Normalise Arguments coming from an #invoke or from a module
-----------------------------------------------------------------------------------
local function prepareArgs(frame)
local origArgs
if frame == mw.getCurrentFrame() then
origArgs = frame:getParent().args
for k, v in pairs(frame.args) do
origArgs = frame.args
break
end
else
origArgs = frame
end
local args = {}
-- searchAlias is the cleaned value of args[1]. args[1] is kept as rawInput for error message
local searchAlias = ''
local rawDisp
for k, v in pairs(origArgs) do
if tonumber(k) == nil then -- Named argment
if k == 'disp' then
rawDisp = v -- Keep raw disp input to pass through plain (wiki)text
args[k] = mw.ustring.lower(v)
elseif k == 'first' then
v = mw.ustring.lower(v)
if v == 'met' or v == 'metric' then
v = 'met'
elseif v == 'imp' or v == 'imperial' then
v = 'imp'
else k = 'trashparam_first' end
args[k] = v
elseif k == 'nowrap' or k == 'wrap' then -- wrap=y deprecated; reading: nowrap=off
v = mw.ustring.lower(v)
if v == '' or v == 'off' or v == 'on' or v == 'all' then
elseif v == 'inline' or (k == 'wrap' and v == 'y') then
v = 'off'
else v = '' end
args['nowrap'] = v
else
args[k] = mw.ustring.lower(v)
end
else
args[k] = v -- Keep rawInput in [1] for error message
if k == 1 then
-- Unnamed argument, the alias to be searched
-- Cleanup
searchAlias = p.normaliseAliasInput(v)
end
end
end
args['searchAlias'] = searchAlias
if rawDisp then args['rawDisp'] = rawDisp end
return args
end
-----------------------------------------------------------------------------------
-- normaliseAliasInput
-----------------------------------------------------------------------------------
function p.normaliseAliasInput(aliasIn)
local a
a = mw.ustring.lower(mw.ustring.gsub(aliasIn, '[%s%,]', ''))
a = mw.ustring.gsub(a, ' ', '')
a = mw.ustring.gsub(a, 'gauge$', '')
a = mw.ustring.gsub(a, "'", "ft")
a = mw.ustring.gsub(a, '"', 'in')
a = mw.ustring.gsub(a, '⁄', '/')
a = mw.ustring.gsub(a, '⁄', '/')
return a
end
-----------------------------------------------------------------------------------
-- debugReturnArgs -- Debug function.
-----------------------------------------------------------------------------------
function p.debugReturnArgs(frame)
local args = prepareArgs(frame)
local retArgs = {}
for k, a in pairs(args) do
table.insert(retArgs, k .. '=' .. a)
end
return 'Args: ' .. table.concat(retArgs, '; ')
end
-----------------------------------------------------------------------------------
-- getTrackGaugeEntry -- Find entry data for a single gauge (alias)
-----------------------------------------------------------------------------------
function p.getTrackGaugeEntry(searchAlias)
gaugeDataAll = mw.loadData(dataPageName)
if searchAlias == '' then
return nil
end
local tgEntry = nil
for i, tgEntry in ipairs(gaugeDataAll) do
for j, alias in ipairs(tgEntry.aliases) do
if alias == searchAlias then
return tgEntry
end
end
end
end
-----------------------------------------------------------------------------------
-- noWrap -- Add span tags to prevent a string from wrapping.
-----------------------------------------------------------------------------------
local function noWrap(s)
return mw.ustring.format('<span class="nowrap">%s</span>', s)
end
-----------------------------------------------------------------------------------
-- frac -- A slimmed-down version of the {{frac}} template (a nowrap is to be added with the unit)
-----------------------------------------------------------------------------------
local function frac(whole, num, den)
-- normally would do the TemplateStyles expansion here, but instead we do
-- it at the callsite because of [[:phab:T200704]]
return mw.ustring.format(
'<span class="frac">%s<span class="num">%s</span>⁄<span class="den">%s</span></span>',
whole and (whole .. '<span class="sr-only">+</span>') or '',
num,
den
)
end
-----------------------------------------------------------------------------------
-- catMentions -- Wikicode for "article mentions gauge" categories
-----------------------------------------------------------------------------------
function p.catMentions(tgEntry, sortlabel, doReturn)
local ns = 'Category:'
local cat
if tgEntry == nil then
-- Parent, the container cat
cat = 'Articles that mention a specific track gauge'
else
cat = 'Articles that mention track gauge ' .. tgEntry.id .. ' mm'
end
-- Argument 'label' can be used to add a catsort. Catsort is not used (as of 20 May 2014)
if sortlabel ~= nil then
sortlabel = '|' .. sortlabel
else
sortlabel = ''
end
if doReturn ~= nil then
if doReturn == 'fullpagename' then
return ns .. cat
elseif doReturn == 'pagename' then -- plaintext, no namespace
return cat
elseif doReturn == 'show' then -- colontrick
return '[[:' .. ns .. cat .. sortlabel .. ']]'
else -- unknown arg value
return ns .. cat
end
else -- Returns straight categorisation (wikitext)
return '[[' .. ns .. cat .. sortlabel .. ']]'
end
end
-----------------------------------------------------------------------------------
-- formatImp -- Formats imperial units size into a single text element
-----------------------------------------------------------------------------------
function p.formatImp(tgEntry, measurementToLink, setNowrap, addUnitlink)
local ret = {}
local ft = tgEntry.ft
if ft then
local ftlink = addUnitlink and measurementToLink ~= 'imp' and '[[Foot (unit)|ft]]' or 'ft'
table.insert(ret, mw.ustring.format('%s %s', ft, ftlink))
end
local inches = tgEntry['in']
local num = tgEntry.num
local den = tgEntry.den
local has_fraction = num and den
if inches and not num and not den then
table.insert(ret, inches)
elseif has_fraction then
table.insert(ret, frac(inches, num, den))
end
if inches or num and den then
local incheslink = addUnitlink and measurementToLink ~= 'imp' and '[[inch|in]]' or 'in'
table.insert(ret, incheslink)
end
local gaugeSize
if setNowrap then
gaugeSize = noWrap(table.concat(ret, ' '))
else
gaugeSize = table.concat(ret, ' ')
end
-- we have do this here to work around [[phab:T200704]]
local templatestyles
if has_fraction then
templatestyles = mw.getCurrentFrame():extensionTag{
name = 'templatestyles', args = { src = 'Fraction/styles.css' }
}
else
templatestyles = ''
end
if measurementToLink == 'imp' and tgEntry.pagename ~= nil then
return mw.ustring.format(
'%s[[%s|%s]]',
templatestyles,
tgEntry.pagename,
gaugeSize
)
else
return templatestyles .. gaugeSize
end
end
-----------------------------------------------------------------------------------
-- formatMet -- Formats metric measurements into a single formatted text element. Public for autodocument
-----------------------------------------------------------------------------------
function p.formatMet(tgEntry, measurementToLink, setNowrap, addUnitlink, removeComma)
local m = tgEntry.m
local gaugeSize
if m then
local mUnit = addUnitlink and measurementToLink ~= 'met' and '[[metre|m]]' or 'm'
gaugeSize = mw.ustring.format('%s %s', m, mUnit)
else
local mm = tgEntry.mm
mm = tonumber(mm)
if mm then
mm = mw.getContentLanguage():formatNum(mm)
if removeComma then
mm = string.gsub( mm, ",", "" )
end
end
local mmUnit = addUnitlink and measurementToLink ~= 'met' and '[[millimetre|mm]]' or 'mm'
gaugeSize = mw.ustring.format('%s %s', mm, mmUnit)
end
if setNowrap then
gaugeSize = noWrap(gaugeSize)
end
if measurementToLink == 'met' and tgEntry.pagename ~= nil then
return mw.ustring.format('[[%s|%s]]', tgEntry.pagename, gaugeSize)
else
return gaugeSize
end
end
-----------------------------------------------------------------------------------
-- formatAltName
-----------------------------------------------------------------------------------
function formatAltName(tgEntry, addGaugeName, addGaugeNameLink, disp, setNowrap, engvar)
-- Assumed: at least one to add is true.
if tgEntry.name == nil then
-- Not checked: link does exist alone
return ''
end
local retAlt = {}
if disp == 'br' then
table.insert(retAlt, '<br />')
else
table.insert(retAlt, ' ')
end
if setNowrap then
table.insert(retAlt, '<span class="nowrap">')
end
if addGaugeNameLink then
if engvar == 'en-us' then
-- Current implementations (2016): metER for metRE (1000-met, 1009-met)
table.insert(retAlt, tgEntry.en_US_link or tgEntry.link or tgEntry.name)
else
table.insert(retAlt, tgEntry.link or tgEntry.name)
end
else -- so must be unlinked .name to add
if engvar == 'en-us' then
-- Current implementations (2016): metER for metRE (1000-met, 1009-met)
table.insert(retAlt, tgEntry.en_US_name or tgEntry.name)
else
table.insert(retAlt, tgEntry.name)
end
end
if setNowrap then --close tag
table.insert(retAlt, '</span>')
end
return table.concat(retAlt, '')
end
-----------------------------------------------------------------------------------
-- main -- The basic module
-----------------------------------------------------------------------------------
function p.main(frame)
-- In general: the tgEntry object (from TG/data) is passed to the functions, while arguments are processed here.
local title = mw.title.getCurrentTitle()
local args = prepareArgs(frame)
local tgEntry = p.getTrackGaugeEntry(args.searchAlias)
-- Categorise & preview warning when no track gauge definition was found.
if tgEntry == nil then
local input = args[1] or ''
local errorTail = require('Module:If preview')._warning({
'Track gauge ' ..
input ..
' not in [[:Template:Track_gauge#List_of_defined_track_gauges|List of defined track gauges]] ([[Template talk:Track gauge|talk]]).'
})
if title:inNamespaces(0, 14) then -- mainspace and category space
errorTail = errorTail .. "[[Category:Articles using Template:Track gauge with unrecognized input]]"
end
return input .. errorTail
end
-- Check and set args & tgEntry props: disp, first, nowrap, first
local disp = args.disp or ''
local first = args.first or tgEntry.def1
local unitlink = args.unitlink or ''
local comma = args.comma or ''
local nowrap = args.nowrap or ''
local setNowrapElement = (nowrap == '' or nowrap == 'off') -- To prevent nested nowrap tags
local measurementToLink
if args.lk == 'on' then
if disp == '1' then
measurementToLink = first -- Can make metric text links to the imp linked page
else
measurementToLink = tgEntry.def1 -- When first=swapped, this could link 2nd measure.
end
end
-- String the text elements together (compose the return table)
local ret = {}
-- nowrap opening tag
if nowrap == 'all' or nowrap == 'on' then
table.insert(ret, '<span class="nowrap">')
end
-- First measure
if first == 'met' then
table.insert(ret,
p.formatMet(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on', comma == 'off'))
else
table.insert(ret,
p.formatImp(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on', comma == 'off'))
end
-- The joint and the second measure
if disp == '1' then
else
local joinText = ''
local closeDisp = ''
if disp == 's' or disp == '/' then
joinText = ' / ' --spaces
elseif disp == 'br' then
joinText = '<br />('
closeDisp = ')'
elseif disp == '[' or disp == '[]' then
joinText = ' ['
closeDisp = ']'
elseif disp ~= '' then -- Is anytext
joinText = ' ' .. args['rawDisp'] .. ' '
else
joinText = ' ('
closeDisp = ')'
end
table.insert(ret, joinText)
if first ~= 'met' then
table.insert(ret,
p.formatMet(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on', comma == 'off'))
else
table.insert(ret,
p.formatImp(tgEntry, measurementToLink, setNowrapElement, unitlink == 'on'))
end
table.insert(ret, closeDisp) -- Could be ''
end
if nowrap == 'on' then -- Closing tag
table.insert(ret, '</span>')
end
-- Alternative name
if args.al == 'on' or args.allk == 'on' then
local setNowrapAltname = (nowrap == '' or nowrap == 'on') -- Logic applied to prevent nested nowrap tags
table.insert(ret, formatAltName(tgEntry, args.al == 'on', args.allk == 'on', disp, setNowrapAltname, args.engvar))
end
-- Closing nowrap tag
if nowrap == 'all' then
table.insert(ret, '</span>')
end
-- Category mentionings (maintenance)
if args.addcat or '' == 'no' then
-- No categorization
elseif title:inNamespaces(0) then
-- switched off per [[Wikipedia:Categories_for_discussion/Log/2016_December_6#Category:Articles_that_mention_a_specific_track_gauge]]
-- 2016-12-19
-- table.insert(ret, p.catMentions(tgEntry))
end
-- Now sting the table together
return table.concat(ret, '')
end
return p
--20161219: maintenance categorisation switched off per CfD
--20170602: fix bug, show name when al=on
--20180708: show preview warning when gauge is not in list
--20190124: with disp=/ (slash) value separator: surround by spaces
--20210304: add option comma=off (mm only)