Module:Track gauge
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 25,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 {{RailGauge}} template.
-- Input can be predefined aliases (see the /data module page)
local p = {}
local gaugeDataAll = nil
local dataPageName = 'Module:RailGauge/data'
-----------------------------------------------------------------------------------
-- formatUnitPlaintext
-- Pattern '00016.5 mm' for tablesort and catsort. Can be wrapped in class="sortkey"
-----------------------------------------------------------------------------------
local function formatUnitPlaintext( rgData, unit, fmtZeroPadding, toFracChar )
-- Returns plaintext (ASCII) only. No css.
if rgData == nil then
return ''
end
if ( unit or rgData.def ) == 'imp' then
local ft = ''
local inch = ''
local frac = ''
if rgData.ft then
ft = rgData.ft .. ' ft'
end
if rgData.num then
frac = ' ' .. rgData.num .. '/' .. rgData.den
if toFracChar then
-- as used in contentCat pagenames
if frac == ' 1/8' then
frac = '⅛'
elseif frac == ' 1/4' then
frac = '¼'
elseif frac == ' 3/8' then
frac = '⅜'
elseif frac == ' 1/2' then
frac = '½'
elseif frac == ' 3/4' then
frac = '¾'
elseif frac == ' 7/8' then
frac = '⅞'
else
frac = frac .. ' (error: fraction character missing in module:RailGauge)'
end
end
if rgData["in"] then
frac = ' ' .. rgData["in"] .. frac .. ' in'
else
frac = frac .. ' in'
end
else
if rgData["in"] then
inch = ' ' .. rgData["in"] .. ' in'
end
end
return mw.text.trim( ft .. inch .. frac )
else
-- metric ( mm )
if fmtZeroPadding == nil or tonumber( fmtZeroPadding ) <= 0 then
return rgData.id .. ' mm'
else
return string.rep( '0',
fmtZeroPadding - string.len( math.floor( tonumber( rgData.id ) ) ) )
.. rgData.id .. ' mm'
end
end
end
-----------------------------------------------------------------------------------
-- anchor -- Anchor text *here* is: <span id="1000 mm">; anchor *there* is: #1000 mm.
-----------------------------------------------------------------------------------
local function anchor( rgEntry, unit, herethere )
local html = require( 'Module:HtmlBuilder' )
if rgEntry == nil then
return ''
end
unit = unit or rgEntry.def1
local anch = formatUnitPlaintext( rgEntry,unit, 0 )
if herethere == 'there' then -- Untested, April 2014
anch = '#' .. anch
else
anch = html.create().tag( 'span' ).attr( 'id', anch )
end
return tostring( anch )
end
-----------------------------------------------------------------------------------
-- catMentionsGaugeSize -- category name for "article mentions gauge" categories
-----------------------------------------------------------------------------------
local function catMentionsGaugeSize( mmSize, catSort, pagename, show, plaintext )
local cat -- hereo
-- Category page name. mmSize has format of id ( like '16.5' ).
cat = 'Category:Articles that mention rail gauge size' .. ' ' .. mmSize .. ' mm'
if plaintext then
return cat
elseif show then
-- uses colon and wikilabel; no catsort
local label = '|cat:mentionings'
cat = '[[:'.. cat .. label .. ']]'
else
if ( catSort or '' ) ~= '' then
catSort = '|' .. catSort
else
catSort = ''
end
cat = '[['.. cat .. catSort .. ']]'
end
return cat
end
-----------------------------------------------------------------------------------
-- catMentionsGaugeSizeParent -- Parent of all "mentions" categories
-----------------------------------------------------------------------------------
local function catMentionsGaugeSizeParent( show )
local cat
-- Category page name
cat = 'Category:Articles that mention a specific rail gauge'
if show then
-- uses colon and wikilabel
cat = '[[:'.. cat .. '|Cat:Articles mentioning RailGauge]]'
end
return cat
end
-----------------------------------------------------------------------------------
-- prepareArgs -- Arguments coming from an #invoke or from a module
-----------------------------------------------------------------------------------
local function prepareArgs( frame )
-- If called via #invoke, use the args passed into the invoking
-- template, or the args passed to #invoke if any exist. Otherwise
-- assume args are being passed directly in from the debug console
-- or from another Lua module.
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
-- Trim whitespace, make lower-case and remove blank arguments for all arguments
-- searchAlias is the cleaned value of [1]. [1] is kept as rawInput for error message
local args = {}
args["searchAlias"] = ''
args["rawInput"] = origArgs[ 1 ] or ''
for k, v in pairs( origArgs ) do
v = mw.text.trim( v )
if tonumber( k ) == nil then
-- Named argment
args[ k ] = mw.ustring.lower( v )
else
-- Unnamed argument, alias to be searched
-- Into lowercase, remove all whitespace, commas to create the search key
v = mw.ustring.lower( mw.ustring.gsub( v, '[%s%,]', '' ) )
args[ k ] = v
if k == 1 then
args["searchAlias"] = v
end
end
end
return args
end
-----------------------------------------------------------------------------------
-- maintReportArgs -- debug feedback, convenience.
-----------------------------------------------------------------------------------
local function maintReportArgs()
local args = prepareArgs( frame )
local report = 'args: '
for k, v in pairs( args ) do
report = report .. k .. '='.. v .. '; '
end
return '<tt>' .. report .. '</tt><br>'
end
-----------------------------------------------------------------------------------
-- getGaugeDataSet -- Find entry data for a single gauge
-----------------------------------------------------------------------------------
local function getGaugeDataSet( searchAlias )
if gaugeDataAll == nil then
gaugeDataAll = mw.loadData( dataPageName )
end
local rgEntry = nil
for i, rgEntry in ipairs( gaugeDataAll ) do
for j, alias in ipairs( rgEntry.aliases ) do
if alias == searchAlias then
return rgEntry
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 to be added with the unit )
-----------------------------------------------------------------------------------
local function frac( whole, num, den )
return mw.ustring.format(
'<span class="frac">%s%s<sup>%s</sup>⁄<sub>%s</sub></span>',
whole or '', whole and '<span class="visualhide"> </span>' or '', num, den
)
end
-----------------------------------------------------------------------------------
-- formatImp -- Formats imperial units size into a single text element
-----------------------------------------------------------------------------------
local function formatImp( rgData, ulink, articleLink, pageName )
local ret = {}
local ft = rgData.ft
if ft then
local ftlink = ulink and not articleLink and '[[Foot (unit)|ft]]' or 'ft'
table.insert( ret, mw.ustring.format( '%s %s', ft, ftlink ) )
end
local inches = rgData['in']
local num = rgData.num
local den = rgData.den
if inches and not num and not den then
table.insert( ret, inches )
elseif num and den then
table.insert( ret, frac( inches, num, den ) )
end
if inches or num and den then
local incheslink = ulink and not articleLink and '[[inch|in]]' or 'in'
table.insert( ret, incheslink )
end
local gaugeSize = noWrap( table.concat( ret, ' ' ) )
if articleLink then
return '[[' .. pageName .. '|' .. gaugeSize .. ']]'
else
return gaugeSize
end
end
-----------------------------------------------------------------------------------
-- formatMet -- Formats metric measurements into a single formatted element
-----------------------------------------------------------------------------------
local function formatMet( rgData, ulink, articleLink, pageName )
local m = rgData.m
local gaugeSize
if m then
local munit = ulink and not articleLink and '[[metre|m]]' or 'm'
gaugeSize = noWrap( mw.ustring.format( '%s %s', m, munit ) )
else
local mm = rgData.mm
mm = tonumber( mm )
if mm then
mm = mw.getContentLanguage():formatNum( mm )
end
local mmunit = ulink and not articleLink and '[[millimetre|mm]]' or 'mm'
gaugeSize = noWrap( mw.ustring.format( '%s %s', mm, mmunit ) )
end
if articleLink then
return '[[' .. pageName .. '|' .. gaugeSize .. ']]'
else
return gaugeSize
end
end
-----------------------------------------------------------------------------------
-- compose -- Puts together the two metric, imperial measures into an output string.
-----------------------------------------------------------------------------------
local function compose( args, rgData )
local definition = rgData.def1
local pageName = rgData.pagename or nil
local imp = formatImp( rgData, args.unitlink == 'on',
args.lk=='on' and definition=='imp' and pageName, pageName )
local met = formatMet( rgData, args.unitlink == 'on',
args.lk=='on' and definition=='met' and pageName, pageName )
local first = args.first or rgData.def1
if first == 'met' or first == 'metric' then
first = 'met'
else
first = 'imp'
end
local ret = {}
if first == 'met' then
table.insert( ret, met )
else
table.insert( ret, imp )
end
local disp = args.disp
if disp ~= '1' then
local formatText
if disp == 's' or disp == '/' then
formatText = '/​%s'
elseif disp == 'or' then
formatText = ' or %s'
elseif disp == '=' then
formatText = ' = %s'
else
formatText = ' (%s)'
end
if first == 'met' then
table.insert( ret, mw.ustring.format( formatText, imp ) )
else
table.insert( ret, mw.ustring.format( formatText, met ) )
end
end
ret = table.concat( ret )
if args.wrap == 'y' then
return ret
else
return noWrap( ret )
end
end
-----------------------------------------------------------------------------------
-- main -- MAIN: the basic module
-----------------------------------------------------------------------------------
function p.main( frame )
local args = nil
local rgData = nil
local title = mw.title.getCurrentTitle()
args = prepareArgs( frame )
-- Get the data entry for this gauge from /data subpage
rgData = getGaugeDataSet( args.searchAlias )
-- Categorise the page if no gauge information was found.
if rgData == nil then
local category = ''
if title:inNamespaces( 0, 14 ) then --main=0, cat=14
category = mw.ustring.format(
'[[Category:Articles with template RailGauge with unrecognized input|%s, %s]]',
args["rawInput"] or ' ', title.text
)
end
return ( args["rawInput"] or '' ) .. category
end
local catMentions = ''
if rgData.id == '1435' then
-- no s.g. categorization
else
local addMentionsCat = args.addcat or 'yes'
if addMentionsCat ~= 'no' then
if title:inNamespaces( 0, 14 ) then
catMentions = catMentionsGaugeSize( rgData.id )
end
end
end
-- Assemble the output.
local ret = {}
table.insert( ret, compose( args, rgData ) )
local gaugeName = rgData.name
local gaugeLink = rgData.link
if args.allk == 'on' and gaugeLink then
table.insert( ret, ' ' .. noWrap( gaugeLink ) )
elseif args.al == 'on' and gaugeName then
table.insert( ret, ' ' .. noWrap( gaugeName ) )
end
table.insert( ret, catMentions )
return table.concat( ret )
end
-----------------------------------------------------------------------------------
-- checkData -- Public. Performs various checks on the /data subpage.
-----------------------------------------------------------------------------------
function p.checkData( frame )
local dataPage = frame and frame.args and frame.args[1] or dataPageName
local data = mw.loadData( dataPage )
local exists, dupes, dupeSort, ret = {}, {}, {}, {}
-- Check for duplicate aliases.
for ti, t in ipairs( data ) do
for ai, alias in ipairs( t.aliases or {} ) do
if not exists[ alias ] then
exists[ alias ] = { ti, ai }
else
if not dupes[ alias ] then
dupes[ alias ] = { exists[ alias ] }
end
table.insert( dupes[ alias ], { ti, ai } )
end
end
end
for alias in pairs( dupes ) do
table.insert( dupeSort, alias )
end
table.sort( dupeSort )
for i1, alias in ipairs( dupeSort ) do
local positions = {}
for i2, aliasKeys in ipairs( dupes[ alias ] ) do
local position = mw.ustring.format( 'gauge %d, alias %d ( gauge id: <code>%s</code> )', aliasKeys[ 1 ], aliasKeys[ 2 ], data[ aliasKeys[ 1 ] ].id or '' )
table.insert( positions, position )
end
local aliasText = mw.ustring.format( 'Duplicate aliases "%s" detected at the following positions: %s.', alias, mw.text.listToText( positions, '; ' ) )
table.insert( ret, aliasText )
end
-- Check for numerators without denominators.
for ti, t in ipairs( data ) do
local num = t.num
local den = t.den
if num and not den then
table.insert( ret, mw.ustring.format( 'Numerator "%s" with no denominator detected at gauge %d ( id: <code>%s</code> ).', num, ti, t.id or '' ) )
elseif den and not num then
table.insert( ret, mw.ustring.format( 'Denominator "%s" with no numerator detected at gauge %d ( id: <code>%s</code> ).', den, ti, t.id or '' ) )
end
end
-- Check for gauges with no imperial or no metric measurements.
for ti, t in ipairs( data ) do
if not ( t.ft or t['in'] or t.num or t.den ) then
table.insert( ret, mw.ustring.format( 'No imperial measurements found for gauge %d ( id: <code>%s</code> ).', ti, t.id or '' ) )
end
if not ( t.m or t.mm ) then
table.insert( ret, mw.ustring.format( 'No metric measurements found for gauge %d ( id: <code>%s</code> ).', ti, t.id or '' ) )
end
end
-- Check for non-numeric measurements.
local measurements = { 'ft', 'in', 'num', 'den', 'm', 'mm' }
for ti, t in ipairs( data ) do
for mi, measurement in ipairs( measurements ) do
local measurementVal = t[ measurement ]
if measurementVal and not tonumber( measurementVal ) then
table.insert( ret, mw.ustring.format( 'Non-numeric <code>%s</code> measurement ( "%s" ) found for gauge %d ( id: <code>%s</code> ).', measurement, measurementVal, ti, t.id or '' ) )
end
end
end
-- Check for gauges with no id.
for ti, t in ipairs( data ) do
if not t.id then
local aliases = {}
for i, alias in ipairs( t.aliases ) do
table.insert( aliases, mw.ustring.format( '<code>%s</code>', alias ) )
end
aliases = mw.ustring.format( ' ( aliases: %s )', mw.text.listToText( aliases ) )
table.insert( ret, mw.ustring.format( 'No id found for gauge %d%s.', ti, aliases or '' ) )
end
end
-- Check for gauges with no aliases.
for ti, t in ipairs( data ) do
if type( t.aliases ) ~= 'table' then
table.insert( ret, mw.ustring.format( 'No aliases found for gauge %d ( id: <code>%s</code> ).', ti, t.id or '' ) )
else
local isAlias = false
for ai, alias in ipairs( t.aliases ) do
isAlias = true
break
end
if not isAlias then
table.insert( ret, mw.ustring.format( 'No aliases found for gauge %d ( id: <code>%s</code> ).', ti, t.id or '' ) )
end
end
end
-- Check for named gauges with no links and gauges with links but no names.
for ti, t in ipairs( data ) do
if t.name and not t.link then
table.insert( ret, mw.ustring.format( 'No link found for the named gauge "%s" at position %d ( id: <code>%s</code> ).', t.name, ti, t.id or '' ) )
elseif t.link and not t.name then
table.insert( ret, mw.ustring.format( 'No name found for the gauge with link "%s" at position %d ( id: <code>%s</code> ).', t.link, ti, t.id or '' ) )
end
end
-- Check for invalid def1 values.
for ti, t in ipairs( data ) do
local def = t.def1
if def ~= 'imp' and def ~= 'met' then
table.insert( ret, mw.ustring.format( 'Invalid def1 value "%s" found for gauge %d ( id: <code>%s</code> ).', def or '', ti, t.id or '' ) )
end
end
-- Check for unwanted whitespace.
for ti, t in ipairs( data ) do
for tkey, tval in pairs( t ) do
if tkey == 'aliases' and type( tval ) == 'table' then
for ai, alias in ipairs( tval ) do
if mw.ustring.find( alias, '%s' ) then
table.insert( ret, mw.ustring.format( 'Unwanted whitespace detected in gauge %d alias %d ( "%s", gauge id: <code>%s</code> ).', ti, ai, alias, t.id or '' ) )
end
end
elseif tkey == 'name' or tkey == 'link' or tkey == 'pagename' or tkey == 'contentcat' then
if tval ~= mw.text.trim( tval ) then
table.insert( ret, mw.ustring.format( 'Unwanted whitespace detected in <code>%s</code> field of gauge %d ( "%s", gauge id: <code>%s</code> ).', tkey, ti, tval, t.id or '' ) )
end
elseif mw.ustring.find( tval, '%s' ) then
table.insert( ret, mw.ustring.format( 'Unwanted whitespace detected in <code>%s</code> field of gauge %d ( "%s", gauge id: <code>%s</code> ).', tkey, ti, tval, t.id or '' ) )
end
end
end
-- Added April 2014: alias should not double with another id ( imp and mm not ambiguous )
local self_id = ''
local self_def = ''
for ti, t in ipairs( data ) do
self_id = t.id
self_def = t.def1
for iC, aliasCheck in ipairs( t.aliases ) do
if tonumber( aliasCheck ) ~= nil then
if self_id ~= aliasCheck then
for iTwo, tTwo in ipairs( data ) do
if aliasCheck == tTwo.id then
table.insert( ret, mw.ustring.format( 'Input alias %s ( %s ) from <code>id=%s mm</code> ambiguous with gauge id=<code>%s mm</code> ( %s )', aliasCheck, self_def, self_id, tTwo.id, tTwo.def1 ) )
end
end
end
end
end
end
-- Return any errors found.
for i, msg in ipairs( ret ) do
ret[ i ] = mw.ustring.format( '<span class="error">%s</span>', msg )
end
if #ret > 0 then
return mw.ustring.format( 'Found the following errors in %s:\n* %s', dataPageName, table.concat( ret, '\n* ' ) )
else
return mw.ustring.format( 'No errors found in %s.', dataPageName )
end
end
-----------------------------------------------------------------------------------
-- documentHeader
-----------------------------------------------------------------------------------
local function documentHeader( numberOfEntries, docTitle, docState )
if docTitle == '' then
if ( numberOfEntries or 0 ) <= 1 then
docTitle = 'Rail gauge'
else
docTitle = 'Rail gauges'
end
end
if docState == '' then
docState = 'collapsible uncollapsed'
else
docState = 'collapsible ' .. docState
end
local sortColHeaders = ''
local sortClass = ''
if ( numberOfEntries or 0 ) > 1 then
sortClass = 'sortable'
sortColHeaders = '' ..
'\n|- ' ..
'\n! style="line-height:90%;" | || || || || || || ||'
end
-- 8 columns
local catMparent = catMentionsGaugeSizeParent( false )
return '' ..
'\n{| class="wikitable ' .. sortClass .. ' ' .. docState .. '" '
.. 'style="text-align:right; width:100%;" ' ..
'\n|+ style="background:#d8d8d8;" | ' .. docTitle ..
'\n|-' ..
'\n!'
.. ' style="background:#d8d8d8;" | Size<br>(mm)' --1
.. '\n! style="background:#d8d8d8;" | Size<br>(ft, in)' --2
.. '\n! style="background:#d8d8d8;" | Size<br>(inches)' --3
.. '\n! style="background:#d8d8d8;" | Units<br> ' --4
.. '\n! style="background:#d8d8d8; width:6em;" | Aliases<br>(input options)' --5
.. '\n! style="background:#d8d8d8; min-width:8em;" | Link<br> ' --6
.. '\n! style="background:#d8d8d8;" | [[:Category:Track gauges by size|Category]]<br>(content)' --7
.. '\n! style="background:#d8d8d8;" | [[:' .. catMparent .. '|Mentionings]]<br>(maintenance)'
.. sortColHeaders
end
-----------------------------------------------------------------------------------
-- documentFooter
-----------------------------------------------------------------------------------
local function documentFooter()
return '\n|}' .. '\n'
end
-----------------------------------------------------------------------------------
-- createcatMentionsGaugeSize -- Create and use preload. Not used after initial creation.
-----------------------------------------------------------------------------------
function createCatMentionsGaugeSize( id )
local preloadUrl = 'action=edit&preload=Template:RailGauge/preload-categorypage-railgauge-mentionings'
local catM = catMentionsGaugeSize( id, nil, nil, nil, true )
local qryString = mw.uri.parseQueryString( preloadUrl )
return tostring( mw.uri.fullUrl( catM, qryString ) )
end
-----------------------------------------------------------------------------------
-- fromInputToId -- Used cleaned Alias as searchkey
-----------------------------------------------------------------------------------
local function fromInputToId( searchAlias )
if gaugeDataAll == nil then
gaugeDataAll = mw.loadData( dataPageName )
end
for i, rgEntry in ipairs( gaugeDataAll ) do
for j, alias in ipairs( rgEntry.aliases ) do
if alias == searchAlias then
return rgEntry.id
end
end
end
-- Second search: by id
if tonumber( searchAlias ) ~= nil then
for i, rgEntry in ipairs( gaugeDataAll ) do
if rgEntry.id == searchAlias then
return rgEntry.id
end
end
end
end
-----------------------------------------------------------------------------------
-- documentInchCount -- Gives the number of inches in decimals.
-----------------------------------------------------------------------------------
local function documentInchCount( rgEntry )
local inches = 0
if rgEntry["num"] ~= nil then
inches = tonumber( ( rgEntry["num"] or 0 ) / ( rgEntry["den"] or 1 ) )
end
inches = tostring( inches + ( tonumber( rgEntry["ft"] or 0 ) * 12 )
+ tonumber( rgEntry["in"] or 0 ) )
return inches
end
-----------------------------------------------------------------------------------
-- documentInchToMm -- Not used lately
-----------------------------------------------------------------------------------
local function documentInchToMm( inchCount )
return tonumber( inchCount or 0 ) * 25.4
end
-----------------------------------------------------------------------------------
-- fromIdToEntrySet
-- From one id, make the set withall one-two-three-more entries ( met, inp, variants )
-----------------------------------------------------------------------------------
local function fromIdToEntrySet( id, searchedAlias )
local TableTools = require( 'Module:TableTools' )
local html = require( 'Module:HtmlBuilder' )
local htmlString = ''
local rowSplit = '<div style="border-top:1px solid #ccc; height:1px;"/>'
-- From the id, build the set of existing entries ( met, imp, and variants )
local entry = {}
local defType = 0
for i, rgEntry in ipairs( gaugeDataAll ) do
if id == rgEntry.id then
if rgEntry.def1 == 'met' and entry[ 1 ] == nil then
entry[ 1 ] = rgEntry
defType = defType +1
elseif rgEntry.def1 == 'imp' and entry[ 2 ] == nil then
entry[ 2 ] = rgEntry
defType = defType + 2
else
entry[ 3 + TableTools.size( entry ) ] = rgEntry
end
end
end
entry = TableTools.compressSparseArray( entry )
-- Entry set is now complete & clean
-- Result: the entry table with entries present in data,
-- In sequence if present ( 1. met, 2. imp, any extra )
if entry[ 1 ] == nil then
-- A non-existent id is entered? Unexpected here.
return '' ..
'\n|-' ..
'\n| colspan=7 style="color:red; text-align:left;" |' ..
'Error using [[Template:RailGauge/document gauge|RailGauge/document gauge]]:' ..
' No rail gauge defined for: "' .. ( searchedAlias or '' ) .. '"'
end
-- Build row from data ( all entries )
-- String together various data elements per cell
local inchCount = documentInchCount( entry[ 1 ] )
-- sortKey
local sortKey = formatUnitPlaintext( entry[ 1 ], 'met', 5 )
htmlString = html.create()
.tag( 'span' ).addClass( 'sortkey' ).wikitext( sortKey )
sortKey = tostring( htmlString )
-- aliases -- listing the input options
local aliasList = {}
for i, e in ipairs( entry ) do
local alis = {}
for j, v in ipairs( e.aliases ) do
if tonumber( v ) == nil then -- No plain numbers
table.insert( alis, tostring( v ) )
end
end
-- cannot sort aliases here ( ? )
for j, v in ipairs( alis ) do
if string.match( v, '^%d' ) == nil then -- textual so to italic. Todo: better uc
local txt = v
htmlString = html.create()
.tag( 'span' ).wikitext( txt ).css( 'font-style', 'italic' )
alis[ j ] = tostring( htmlString )
end
end
table.insert ( aliasList, table.concat( alis, '; ' ) )
end
-- def -- Definition unit ( def1 in data )
local def = {} -- definition code ( 'met' or 'imp' )
local defText = {}
for i, v in ipairs ( entry ) do
table.insert( def, v.def1 )
if v.def1 == 'imp' then
table.insert( defText, 'imperial' )
else
table.insert( defText, 'metric' )
end
end
-- mm; ft in -- Measurement ( number & unit; met and imp; anchor to here )
local measure = {}
local unitanchor = { '', '' }
measure[ 1 ] = formatMet( entry[ 1 ] )
measure[ 2 ] = formatImp( entry[ 1 ] ) -- both met and imp from entry[ 1 ]
if math.fmod( defType, 2 ) == 1 then
htmlString = html.create()
.tag( 'span' ).wikitext( measure[ 1 ] ).css( 'font-weight', 'bold' )
measure[ 1 ] = tostring( htmlString )
unitanchor[ 1 ] = anchor( entry[ 1 ], 'met' )
end
if defType >= 2 then
htmlString = html.create()
.tag( 'span' ).wikitext( measure[ 2 ] ).css( 'font-weight', 'bold' )
measure[ 2 ] = tostring( htmlString )
unitanchor[ 2 ] = anchor( entry[ 1 ], 'imp' )
end
-- Linked page
local linkPage = {}
for i, e in ipairs( entry ) do
table.insert( linkPage, e.pagename )
end
if #linkPage == 2 then
if linkPage[ 1 ] == linkPage[ 2 ] then
linkPage[ 2 ] = nil
end
end
for i, lp in ipairs( linkPage ) do
local fmtLp = ''
if string.len( lp ) > 15 then
fmtLp = '[[' .. lp .. ']]'
else
htmlString = html.create()
.tag( 'span' ).wikitext( lp ).addClass( 'nowrap' )
htmlString = tostring( htmlString )
fmtLp = '[[' .. lp .. '|' .. htmlString .. ']]'
end
htmlString = html.create()
.tag( 'span' ).css( 'text-align', 'left' ).wikitext( fmtLp )
linkPage[ i ] = tostring( htmlString )
end
-- catContent -- This is a possible category with content (not maintenance)
-- can be hardcoded in the data, or test by size pattern
local catContent = {}
local catTtl
local label
local catCsuffix = ' gauge railways'
for i, e in ipairs( entry ) do
if e.contentcat ~= nil then
label = string.match( e.contentcat, '([%S]*)' ) or 'nomatch'
table.insert( catContent,
'[[:Category:' .. e.contentcat .. '|cat:' .. label .. ']]' )
end
end
if #catContent == 0 then
if math.fmod( defType, 2 ) == 1 then
label = formatUnitPlaintext( entry[ 1 ], 'met' )
catTtl = mw.title.makeTitle( 14, label .. catCsuffix )
if catTtl.exists then
table.insert( catContent,
'[[:' .. catTtl.fullText .. '|cat:' .. noWrap( label ) .. ']]' )
end
end
if defType >= 2 then
label = formatUnitPlaintext( entry[ 1 ], 'imp', nil, true )
catTtl = mw.title.makeTitle( 14, label .. catCsuffix )
if catTtl.exists then
table.insert( catContent,
'[[:' .. catTtl.fullText .. '|cat:' .. noWrap( label ) .. ']]' )
end
end
end
-- Mentions category
local catMentions = catMentionsGaugeSize( id, catSort, title, true )
htmlString = html.create()
.tag( 'span' ).css( 'text-align', 'left' ).wikitext( catMentions )
catMentions = tostring( htmlString )
-- Create this cat (temporal, initial only)
local testTitle = mw.title.getCurrentTitle()
local createCat = ''
if testTitle.namespace == 2 then
createCat = '[' .. createCatMentionsGaugeSize( id ) .. ' c]'
end
-- Compose the id-row with all cell values
local row = {}
table.insert( row, sortKey .. unitanchor[ 1 ] .. measure[ 1 ] ) --1 met
table.insert( row, sortKey .. unitanchor[ 2 ] .. measure[ 2 ] ) --2 imp
table.insert( row, sortKey .. inchCount ) --3
table.insert( row, table.concat( defText, rowSplit ) ) --4
table.insert( row, table.concat( aliasList, rowSplit ) ) --5
table.insert( row, table.concat( linkPage, rowSplit ) ) --6
table.insert( row, table.concat( catContent, rowSplit ) ) --7
table.insert( row, catMentions ) --8
return '' ..
'\n|- style="background:#e8e8e8; border-top:2px solid #aaa;" | ' ..
'\n|' .. table.concat( row, ' || ' )
end
-----------------------------------------------------------------------------------
-- documentGauge -- Selfdocument gauge data ( one, multiple, range, all )
-----------------------------------------------------------------------------------
function p.documentGauge( frame )
local TableTools = require( 'Module:TableTools' )
local args = prepareArgs( frame )
gaugeDataAll = mw.loadData( dataPageName )
-- Series from the list
-- idFrom and idTo are numerical
local rgList = {}
local idFrom = -1
local idTo = -1
for i, v in ipairs( args ) do
if v == 'all' then
idFrom = -math.huge
idTo = math.huge
break
end
end
if args.docfrom ~= nil then
idFrom = tonumber( fromInputToId( args.docfrom )
or mw.ustring.gsub( '0' .. args.docfrom, 'mm', '' ) )
idTo = math.huge
end
if args.docto ~= nil then
idTo = tonumber( fromInputToId( args.docto )
or mw.ustring.gsub( '0' .. args.docto, 'mm', '' ) )
end
if idTo > 0 then -- some list is requested from the whole data set
if idFrom > idTo then
local dummy = idFrom
idFrom = idTo
idTo = dummy
end
for i, rgEntry in ipairs( gaugeDataAll ) do
if ( tonumber( rgEntry.id ) >= idFrom )
and ( tonumber( rgEntry.id ) <= idTo ) then
table.insert( rgList, tonumber( rgEntry.id ) )
end
end
rgList = TableTools.removeDuplicates( rgList )
table.sort( rgList )
end
-- Individual entries can be mentioned in args ( all unnamed = numbered params )
-- Need a straight table to keep sequence right
local argsAliases = TableTools.compressSparseArray( args )
for i, argsAlias in ipairs( argsAliases ) do
id = fromInputToId( argsAlias )
if id ~= nil then
-- Add to the top
table.insert( rgList, i, tonumber( id ) )
end
end
-- Now loop through the prepared rgList[id] and add rows to result table
-- One row contains all available entries for the id ( met, imp, a third variant )
local rowRGid = {}
for i, numId in ipairs( rgList ) do
table.insert( rowRGid, fromIdToEntrySet( tostring( numId ) ) )
end
return documentHeader( #rgList, args.doctitle or '', args.docstate or '' ) ..
table.concat( rowRGid, '' ) .. documentFooter()
end
-----------------------------------------------------------------------------------
-- gaugeSizeFromTitle
-- Currently finds "1620 mm" when at end of title, then returns "1620". Blank when not found.
-- Used for cat:mentions category page.
-----------------------------------------------------------------------------------
function p.gaugeSizeFromTitle()
local title = mw.title.getCurrentTitle()
return string.match( title.text, '%s(%d+%.?%d*)%smm$' ) or ''
end
-----------------------------------------------------------------------------------
-- catSortFromTitle
-- Currently finds "600 mm" when at end of title, then returns "0600 mm" (for catSort).
-- Blank when not found. Used for cat:mentions category page.
-----------------------------------------------------------------------------------
function p.catSortFromTitle()
local title = mw.title.getCurrentTitle()
local catSort = string.match( title.text, '%s(%d+%.?%d*)%smm$' ) or ''
if catSort ~= '' then
catSort = string.rep( '0',
4 - string.len( math.floor( tonumber( catSort ) ) ) )
.. catSort .. ' mm'
end
if catSort == '' then
return '*'
else
return catSort
end
end
return p