Difference between revisions of "Module:Adjacent stations"
blackwiki>Jc86035 m (prevent some matches) |
blackwiki>Jc86035 (sync changes by Ythlev) |
||
| Line 1: | Line 1: | ||
| − | + | local p, data, defaultData, lineData, typeData, isFuncAdjacent = {} | |
| − | + | local function dig ( ... ) | |
| − | local p = {} | + | -- Digs through a table with sub-tables using arguments as keys, returning the value of the last key argument |
| − | + | -- Analogous to returning a file given a file path with sub-folders | |
| − | local | + | -- Returns nil if any given sub-table does not exist |
| − | + | local arg, n = { ... }, select ( '#', ... ) | |
| − | + | local a, i = arg[1], 1 | |
| − | + | while a and i < n do | |
| − | + | a = a[arg[i + 1]] | |
| − | + | i = i + 1 | |
| − | |||
| − | -- | ||
| − | - | ||
| − | |||
| − | -- | ||
| − | |||
| − | |||
| − | -- | ||
| − | - | ||
| − | |||
| − | |||
| − | |||
| − | local | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| + | return a or nil | ||
end | end | ||
| − | + | local function makeInvokeFunc ( funcName ) | |
| − | + | return function ( frame ) | |
| − | + | local args = require ( 'Module:Arguments' ).getArgs ( frame ) | |
| − | local function | + | if funcName == '_adjacent' then |
| − | + | isFuncAdjacent = true | |
| − | + | local tableTools = require ( 'Module:TableTools' ) | |
| − | + | args = tableTools.numData ( args ) | |
| − | + | if args.other then | |
| − | + | args[1] = args[1] or {} | |
| − | + | for k, _ in pairs ( args.other ) do args[1][k] = args[1][k] or args['other'][k] end | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | return p[funcName]( tableTools.compressSparseArray ( args )) | |
| − | + | else | |
| − | + | args.system = args.system or args[1] | |
| − | + | if args.system then | |
| − | + | local s = 'Module:Adjacent stations/' .. args.system | |
| − | + | data = mw.title.new ( s ).exists and mw.loadData ( s ) | |
| − | |||
| − | |||
end | end | ||
| − | + | if funcName ~= '_infobox' then | |
| − | + | args.line = args.line or args[funcName == '_station' and 3 or 2] | |
| − | + | if data and args.line then | |
| − | + | args.line = | |
| − | + | dig ( data, 'lines', args.line ) and args.line or | |
| − | + | dig ( data, 'aliases', string.lower ( args.line )) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | args['type'] = args['type'] or args[funcName == '_station' and 4 or 3] | |
| − | + | if funcName ~= '_station' then | |
| − | if | + | defaultData = dig ( data, 'lines', '_default' ) |
| − | + | lineData = dig ( data, 'lines', args.line ) | |
| − | + | typeData = dig ( lineData, 'types', args['type'] ) | |
| − | |||
| − | |||
| − | |||
end | end | ||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | return p[funcName]( args, frame ) | |
| − | return | ||
end | end | ||
end | end | ||
| − | + | end | |
| − | local | + | p.infobox = makeInvokeFunc ( '_infobox' ) |
| − | + | function p._infobox ( args, frame ) | |
| − | + | local data = dig ( data, 'infobox station') or data | |
| − | elseif | + | if args[3] == 'header' then return |
| − | return { | + | dig ( data, 'header', args[2] or 1) or |
| + | dig ( data, 'name format', args[2] or 1) or | ||
| + | (args[2] or args.system) and frame:expandTemplate { | ||
| + | title = ( args[2] or args.system ) .. ' style', | ||
| + | args = { 'name_format' } | ||
| + | } | ||
| + | elseif args[3] == 'sub-header' then | ||
| + | if dig ( data, 'sub-header') then | ||
| + | return dig ( data, 'sub-header', args[2] or 1) | ||
| + | else | ||
| + | local t = {} | ||
| + | t[1] = 'background:' | ||
| + | t[2] = | ||
| + | dig ( data, 'header background color', args[2] or 1) or | ||
| + | (args[2] or args.system) and frame:expandTemplate { | ||
| + | title = ( args[2] or args.system ) .. ' style', | ||
| + | args = { 'thbgcolor' } | ||
| + | } or | ||
| + | '#EFEFEF' | ||
| + | t[2] = string.match ( t[2], '#') and t[2] or '#' .. t[2] | ||
| + | t[3] = ';color:' | ||
| + | t[4] = | ||
| + | dig ( data, 'header text color', args[2] or 1) or | ||
| + | (args[2] or args.system) and frame:expandTemplate { | ||
| + | title = ( args[2] or args.system ) .. ' style', | ||
| + | args = { 'thcolor' } | ||
| + | } or | ||
| + | require ( 'Module:Color contrast' )._greatercontrast ({ t[2] }) | ||
| + | t[4] = string.match ( t[4], '#') and t[4] or '#' .. t[4] | ||
| + | return table.concat ( t ) | ||
end | end | ||
| − | |||
end | end | ||
| − | + | end | |
| − | + | local function stationTitle ( station, args, n ) | |
| − | + | if station and data then | |
| − | + | local data = isFuncAdjacent and data[n] or data | |
| − | + | local line = isFuncAdjacent and args[n]['line'] or args['line'] | |
| − | + | local typ = isFuncAdjacent and args[n]['type'] or args['type'] | |
| − | data | + | local link |
| − | + | if type ( data['station format'] ) == 'table' then | |
| − | + | local defaultFormat = data['station format'] | |
| − | + | if type ( defaultFormat[station] ) == 'table' then | |
| − | + | local stationFormat = defaultFormat[station] | |
| − | local | + | if line then |
| − | + | line = | |
| − | + | stationFormat[line] and line or | |
| − | + | dig ( data, 'aliases', string.lower ( line )) | |
| − | + | end | |
| − | + | if type ( stationFormat[line] ) == 'table' then | |
| − | + | local lineFormat = stationFormat[line] | |
| − | + | link = lineFormat[typ] or lineFormat[1] | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | if | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | if | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | if | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | ( | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | if | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
else | else | ||
| − | + | link = stationFormat[line] or stationFormat[1] | |
| − | |||
end | end | ||
| − | + | elseif type ( defaultFormat[station] ) == 'number' then | |
| − | + | link = defaultFormat[defaultFormat[station]] | |
| − | + | else | |
| − | + | link = defaultFormat[station] or defaultFormat[1] | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| + | else | ||
| + | link = data['station format'] | ||
end | end | ||
| − | + | link = ( string.gsub ( link, '%%1', station )) | |
| − | + | return | |
| − | + | string.match ( link, '%[%[.-%]%]' ) and link or | |
| − | table. | + | table.concat ({'[[', link, '|', station, ']]' }) |
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | end | |
| − | + | p.station = makeInvokeFunc ( '_station' ) | |
| − | + | function p._station ( args, frame ) | |
| − | + | args.station = args.station or args[2] | |
| − | + | if data then | |
| − | + | return stationTitle ( args.station, args ) | |
| − | + | else | |
| − | + | return frame:expandTemplate { | |
| − | + | title = args.system and args.system .. ' stations', | |
| − | + | args = { | |
| − | + | ['station'] = args.station, | |
| + | ['line'] = args.line, | ||
| + | ['branch'] = args['type'] | ||
| + | } | ||
| + | } | ||
end | end | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | p.color = makeInvokeFunc ( '_color' ) | |
| − | + | function p._color ( args, frame ) | |
| − | + | if data then | |
| − | + | return mw.text.nowiki ( | |
| − | + | typeData and typeData['color'] or | |
| − | + | lineData and lineData['color'] or | |
| − | return | + | defaultData and defaultData['color'] |
| − | + | ) | |
| − | + | else | |
| + | return frame:expandTemplate { | ||
| + | title = args.system and args.system .. ' color', | ||
| + | args = { args.line, ['branch'] = args['type'] } | ||
| + | } | ||
end | end | ||
end | end | ||
| − | + | local root = mw.html.create ( 'div' ) | |
| − | + | local function renderBox ( style, colour, lineName, lineTitle ) | |
| − | + | if colour then | |
| − | function | + | colour = string.match ( colour, '#' ) and colour or '#' .. colour |
| − | |||
| − | if | ||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | local box = mw.html.create ( 'span' ) | |
| − | + | -- Colour settings | |
| − | + | if | |
| − | + | style == 'dot' or | |
| − | + | style == 'ldot' or | |
| − | local | + | style == 'square' or |
| − | + | style == 'lsquare' or | |
| − | + | style == 'xroute' then | |
| − | + | box:css ( 'color', colour ) | |
| − | + | else | |
| − | + | box:css ( 'background-color', colour ) | |
| − | + | if style == 'route' or style == 'croute' then | |
| − | + | box | |
| − | + | :css ( 'color', | |
| − | + | typeData and typeData['text color'] or | |
| − | + | lineData and lineData['text color'] or | |
| − | + | require ( 'Module:Color contrast' )._greatercontrast ({ colour }) | |
| − | + | ) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | end | |
| − | + | -- Border settings | |
| − | + | if | |
| − | + | style == 'legend' or style == nil or | |
| − | + | style == 'linked' or style == 'link' or | |
| − | + | style == 'inline' or style == 'yes' or | |
| − | + | style == 'box' then | |
| − | + | box:css ( 'border', '1px solid black' ) | |
| − | + | elseif style and string.match ( style, 'route' ) then | |
| + | box | ||
| + | :css ( 'border', '.075em solid ' .. ( | ||
| + | typeData and typeData['border color'] or | ||
| + | lineData and lineData['border color'] or | ||
| + | colour | ||
| + | ) | ||
| + | ) | ||
| + | if style ~= 'route' then | ||
| + | box:css ( 'border-radius', '.5em' ) | ||
end | end | ||
| − | + | end | |
| − | + | -- Additional style-specific settings | |
| − | + | if style == 'legend' or style == nil then | |
| − | + | root | |
| − | + | :addClass ( 'legend' ) | |
| − | + | :css ( '-webkit-column-break-inside', 'avoid' ) | |
| − | + | :css ( 'page-break-inside', 'avoid' ) | |
| − | + | :css ( 'break-inside', 'avoid-column' ) | |
| − | + | box | |
| − | + | :addClass ( 'legend-color' ) | |
| − | + | :css ( 'display', 'inline-block' ) | |
| − | + | :css ( 'width', '1.5em' ) | |
| − | + | :css ( 'height', '1.5em' ) | |
| − | + | :css ( 'margin', '1px' ) | |
| − | + | elseif | |
| − | + | style == 'dot' or | |
| − | + | style == 'ldot' or | |
| − | + | style == 'square' or | |
| − | + | style == 'lsquare' then | |
| − | + | box:css ( 'line-height', 'initial' ) | |
| − | + | elseif style and string.match ( style, 'route' ) then | |
| − | + | box | |
| − | + | :css ( 'font-weight', 'bold' ) | |
| − | + | :css ( 'font-size', 'inherit' ) | |
| − | + | :css ( 'white-space', 'nowrap' ) | |
| − | + | :css ( 'padding', '0 .3em' ) | |
| − | + | end | |
| − | + | -- Text for the span tag | |
| − | + | local boxText = { | |
| − | + | ['inline'] = string.rep ( ' ',4 ), ['yes'] = string.rep ( ' ', 4 ), | |
| − | + | ['box'] = string.rep ( ' ', 4 ), | |
| − | + | ['linked'] = string.rep ( ' ', 4 ), ['link'] = string.rep ( ' ', 4 ), | |
| − | + | ['small'] = string.rep ( ' ', 1 ), | |
| − | + | ['legend'] = string.rep ( ' ', 1 ), | |
| − | + | ['dot'] = '●', | |
| − | + | ['ldot'] = '●', | |
| − | + | ['square'] = '■', | |
| − | + | ['lsquare'] = '■', | |
| − | + | ['route'] = lineName, | |
| − | + | ['croute'] = lineName, | |
| − | + | ['xroute'] = lineName | |
| − | if | + | } |
| − | + | box:wikitext ( boxText[style] or string.rep ( ' ', 1 )) | |
| − | + | -- Adds link to text | |
| − | + | if | |
| − | + | style == 'linked' or style == 'link' or | |
| + | style == 'ldot' or | ||
| + | style == 'lsquare' or | ||
| + | style and string.match ( style, 'route' ) then | ||
| + | if string.match ( lineTitle, '%[%[.-%]%]' ) then | ||
| + | if string.match ( lineTitle, '|' ) then | ||
| + | root:wikitext (( string.gsub ( lineTitle, '%[%[(.-)|.-%]%]', '[[%1|' .. tostring ( box ) .. ']]' ))) | ||
else | else | ||
| − | + | root:wikitext (( string.gsub ( lineTitle, '%[%[(.-)%]%]', '[[%1|' .. tostring ( box ) .. ']]' ))) | |
| − | |||
| − | |||
end | end | ||
else | else | ||
| − | + | root:wikitext ( tostring ( box )) | |
end | end | ||
| − | + | else | |
| − | + | root:wikitext ( tostring ( box )) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
end | end | ||
| − | + | p.line = makeInvokeFunc ( '_line' ) | |
| − | p. | + | function p._line ( args, frame ) |
| − | + | if data then | |
| − | function p. | + | local s = |
| − | local | + | typeData and typeData['title'] and table.concat ({ lineData['title'], ' (', typeData['title'], ')' }) or |
| − | + | lineData and lineData['title'] or | |
| − | + | defaultData and ( string.gsub ( defaultData['title'], '%%1', args.line or '_default' )) | |
| − | + | if args.icon then | |
| − | + | if args.icon == 'image' then | |
| − | + | args.style = nil | |
| − | + | return p._icon ( args ) .. ' ' .. s | |
| − | + | elseif | |
| − | + | args.icon == 'legend' or | |
| − | + | args.icon == 'inline' or | |
| − | + | args.icon == 'small' or | |
| − | if | + | args.icon == 'dot' or |
| − | if | + | args.icon == 'square' then |
| − | + | renderBox ( args.icon, p._color ( args ), args.line, s ) | |
| − | + | root:wikitext ( ' ', s ) | |
| − | + | return root | |
| − | icon = | ||
| − | |||
| − | |||
| − | |||
| − | icon | ||
end | end | ||
| + | else | ||
| + | return s | ||
end | end | ||
| − | + | else | |
| − | + | return frame:expandTemplate { | |
| − | + | title = args.system and args.system .. ' lines', | |
| − | + | args = { args.line, ['branch'] = args['type'] } | |
| − | + | } | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
end | end | ||
| − | + | p.icon = makeInvokeFunc ( '_icon' ) | |
| − | p.icon = | + | function p._icon ( args, frame ) |
| − | + | if data then | |
| − | function p. | + | local s = |
| − | local | + | typeData and typeData['icon'] or |
| − | + | lineData and lineData['icon'] or | |
| − | + | data and data['system icon'] | |
| − | + | if | |
| − | + | not s or | |
| − | + | args.style == 'box' or | |
| − | + | args.style == 'linked' or args.style == 'link' or | |
| − | + | args.style == 'ldot' or | |
| − | + | args.style == 'lsquare' or | |
| − | + | args.style and string.match ( args.style, 'route' ) then | |
| − | + | renderBox ( args.style or 'inline', p._color ( args ), args.line, p._line ( args )) | |
| − | + | return root | |
| − | |||
| − | |||
else | else | ||
| − | + | return s | |
| − | |||
end | end | ||
| − | + | else | |
| − | + | return frame:expandTemplate { | |
| − | + | title = 'Rail-interchange', | |
| − | + | args = { string.lower ( args.system ), string.lower ( args.line ), ['size'] = args.size } | |
| − | + | } | |
| − | + | end | |
| − | + | end | |
| − | + | p.box = makeInvokeFunc ( '_box' ) | |
| − | + | function p._box ( args, frame ) | |
| + | local lineTitle = p._line ( args, frame ) | ||
| + | local style = | ||
| + | args.style or args.inline or args[3] or | ||
| + | dig ( typeData, 'icon format' ) or | ||
| + | dig ( lineData, 'icon format' ) or | ||
| + | dig ( data, 'system icon format' ) | ||
| + | renderBox ( style, p._color ( args, frame ), args.line, lineTitle ) | ||
| + | if | ||
| + | style == 'legend' or style == nil or | ||
| + | style == 'inline' or style == 'yes' or | ||
| + | style == 'small' or | ||
| + | style == 'dot' or | ||
| + | style == 'square' then | ||
| + | root:wikitext ( ' ', lineTitle ) | ||
end | end | ||
| + | return root | ||
end | end | ||
| − | + | p.main = makeInvokeFunc ( '_adjacent' ) | |
| − | p. | + | p.adjacent = makeInvokeFunc ( '_adjacent' ) |
| − | + | function p._adjacent ( args ) | |
| − | function p. | + | local yesNo = require ( 'Module:Yesno' ) |
| − | local | + | local i18n = require ( 'Module:Adjacent stations/i18n' ) |
| − | local | + | local root, lang = mw.html.create ( 'table' ), 'en-GB' |
| − | + | root:addClass ( 'wikitable adjacent-stations' ) | |
| − | + | local function renderHeader ( stopNoun, systemIcon, systemTitle ) | |
| − | + | root | |
| − | local | + | :tag ( 'tr' ) |
| − | + | :tag ( 'th' ) | |
| − | + | :addClass ( 'hcA' ) | |
| − | + | :wikitext ( i18n[lang]['preceding']( stopNoun )) | |
| − | + | :done () | |
| − | + | :tag ( 'th' ) | |
| − | + | :attr ( 'colspan', 3 ) | |
| − | + | :css ( 'vertical-align', 'middle' ) | |
| − | + | :wikitext ( | |
| − | + | systemIcon and systemTitle and systemIcon .. ' ' .. systemTitle or | |
| − | + | systemTitle or | |
| − | + | systemIcon | |
| − | + | ) | |
| − | + | :done () | |
| − | + | :tag ( 'th' ) | |
| + | :addClass ( 'hcA' ) | ||
| + | :wikitext ( i18n[lang]['following']( stopNoun )) | ||
| + | end | ||
| + | local function renderSubHeader ( subHeader ) | ||
| + | root | ||
| + | :tag ( 'tr' ) | ||
| + | :tag ( 'th' ) | ||
| + | :attr ( 'colspan', 5 ) | ||
| + | :addClass ( 'hmA' ) | ||
| + | :wikitext ( subHeader ) | ||
| + | end | ||
| + | local function renderSideCell ( row, rowSpan, adjacent, terminus, oneWay, circular, through, Reverse, note ) | ||
| + | local mainText, subText = mw.html.create ( 'div' ) | ||
| + | if adjacent then | ||
| + | mainText:wikitext ( adjacent ) | ||
| + | subText = mw.html.create ( 'div' ) | ||
| + | subText:addClass ( 'isA' ) | ||
| + | if adjacent == terminus then | ||
| + | subText:wikitext ( 'Terminus' ) | ||
else | else | ||
| − | + | subText:wikitext ( oneWay and 'one-way operation' or circular and terminus or i18n[lang]['towards']( terminus )) | |
end | end | ||
else | else | ||
| − | + | mainText:css ( 'font-style', 'italic' ) | |
| + | mainText:wikitext ( Reverse and 'Reverses direction' or through and i18n[lang]['through']( through ) or 'Terminus' ) | ||
| + | end | ||
| + | row | ||
| + | :tag ( 'td' ) | ||
| + | :attr ( 'rowspan', rowSpan ) | ||
| + | :addClass ( 'bcA' ) | ||
| + | :node ( mainText ) | ||
| + | :tag ( 'div' ) | ||
| + | :css ( 'font-size', 'smaller' ) | ||
| + | :wikitext ( note ) | ||
| + | :done () | ||
| + | :node ( subText ) | ||
| + | end | ||
| + | local function renderMidCells ( row, rowSpan, colour, backgroundColour, lineTitle, typeTitle, note, transfer ) | ||
| + | if colour then | ||
| + | colour = string.match ( colour, '#' ) and colour or '#' .. colour | ||
| + | end | ||
| + | row | ||
| + | :tag ( 'td' ) | ||
| + | :attr ( 'rowspan', rowSpan ) | ||
| + | :addClass ( 'bbA' ) | ||
| + | :css ( 'background-color', colour ) | ||
| + | :done () | ||
| + | :tag ( 'td' ) | ||
| + | :attr ( 'rowspan', rowSpan ) | ||
| + | :addClass ( 'bcA' ) | ||
| + | :css ( 'background-color', backgroundColour ) | ||
| + | :wikitext ( lineTitle ) | ||
| + | :tag ( 'div' ) | ||
| + | :wikitext ( typeTitle ) | ||
| + | :done () | ||
| + | :tag ( 'div' ) | ||
| + | :css ( 'font-size', 'smaller' ) | ||
| + | :wikitext ( note ) | ||
| + | :done () | ||
| + | :tag ( 'div' ) | ||
| + | :addClass ( 'isA' ) | ||
| + | :wikitext ( i18n[lang]['transfer']( transfer )) | ||
| + | :done () | ||
| + | :done () | ||
| + | :tag ( 'td' ) | ||
| + | :attr ( 'rowspan', rowSpan ) | ||
| + | :addClass ( 'bbA' ) | ||
| + | :css ( 'background-color', colour ) | ||
| + | end | ||
| + | local function renderNonStopRow ( title, colour, isFormer ) | ||
| + | if colour then | ||
| + | colour = string.match ( colour, '#' ) and colour or '#' .. colour | ||
end | end | ||
| − | + | root | |
| − | + | :tag ( 'tr' ) | |
| + | :tag ( 'td' ) | ||
| + | :attr ( 'colspan', 5 ) | ||
| + | :addClass ( 'bcA' ) | ||
| + | :tag ( 'div' ) | ||
| + | :tag ( 'span' ) | ||
| + | :css ( 'border', '1px solid black' ) | ||
| + | :css ( 'background-color', colour ) | ||
| + | :wikitext ( string.rep ( ' ', 4 )) | ||
| + | :done () | ||
| + | :wikitext ( ' ', isFormer == true and i18n[lang]['nonstop_past']( title ) or i18n[lang]['nonstop_present']( title )) | ||
end | end | ||
| − | + | local function renderNoteRow ( note ) | |
| − | + | root | |
| − | + | :tag ( 'tr' ) | |
| − | + | :tag ( 'td' ) | |
| − | + | :attr ( 'colspan', 5 ) | |
| − | + | :addClass ( 'bcA' ) | |
| − | + | :wikitext ( note ) | |
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | + | local function makeTerminusFunc ( n, fallback ) | |
| − | local | + | return function ( side ) |
| − | if type( | + | local termini = fallback ( side .. ' terminus' ) |
| − | + | if type ( termini ) == 'string' then | |
| − | + | return stationTitle ( termini, args, n ) | |
| − | + | elseif type ( termini ) == 'table' then | |
| + | local i, t, to = 1, {}, args[n]['to-' .. side] or args[n]['to'] | ||
| + | while termini[i] and to ~= termini[i] do | ||
| + | t[i] = stationTitle ( termini[i], args, n ) | ||
| + | i = i + 1 | ||
end | end | ||
| + | local via = stationTitle ( termini['via'], args, n ) | ||
| + | return | ||
| + | stationTitle ( termini[i], args, n ) or | ||
| + | via and mw.text.listToText ( t, nil, ' or ' ) .. ' via ' .. via or | ||
| + | mw.text.listToText ( t, nil, ' or ' ) | ||
end | end | ||
| − | |||
end | end | ||
| − | + | end | |
| − | + | data = {} | |
| − | + | local j, k, l = 2, 2, 2 | |
| − | + | for i, v in ipairs ( args ) do | |
| − | + | if v.header then renderSubHeader ( v.header ) end | |
| − | + | args[i]['system'] = args[i]['system'] or i > 1 and args[i - 1]['system'] | |
| − | + | if args[i]['system'] then | |
| − | + | data[i] = mw.loadData ( 'Module:Adjacent stations/' .. args[i]['system'] ) | |
| − | + | lang = dig ( data[i], 'lang' ) or 'en-GB' | |
| − | + | defaultData = function ( n ) return dig ( data[n], 'lines', '_default' ) end | |
| − | + | if args[i]['line'] then | |
| − | + | args[i]['line'] = | |
| − | + | dig ( data[i], 'lines', args[i]['line'] ) and args[i]['line'] or | |
| − | + | dig ( data[i], 'aliases', string.lower ( args[i]['line'] )) or | |
| − | + | error ( i18n[lang]['error_unknown']( args[i]['line'] )) | |
else | else | ||
| − | + | args[i]['line'] = i == 1 and '_default' or args[i - 1]['line'] | |
| − | + | end | |
| − | + | lineData = function ( n, line ) return | |
| + | dig ( data[n], 'lines', line or v.line ) or | ||
| + | dig ( data[n], 'lines', dig ( data[n], 'aliases', string.lower ( line or v.line ))) | ||
| + | end | ||
| + | typeData = function ( n ) return dig ( lineData ( n ), 'types', v['type'] ) end | ||
| + | local function fallback ( parameter, n ) | ||
| + | return dig ( typeData ( n or i ), parameter ) or dig ( lineData ( n or i ), parameter ) or dig ( defaultData ( n or i ), parameter ) | ||
end | end | ||
| − | + | local terminus = makeTerminusFunc ( i, fallback ) | |
| − | + | if i == 1 or args[i]['system'] ~= args[i - 1]['system'] then | |
| − | + | renderHeader ( | |
| − | + | data[i]['header stop noun'] or i18n[lang]['stop_noun'], | |
| − | + | data[i]['system icon'], | |
| − | + | data[i]['system title'] | |
| − | + | ) | |
| − | + | end | |
| − | + | if v.nonstop then | |
| − | + | renderNonStopRow ( fallback ( 'title' ), fallback ( 'color' ), v.nonstop == 'former' ) | |
| − | + | else | |
| − | + | local row = root:tag ( 'tr' ) | |
| − | + | if i > j - 2 then | |
| − | + | while args[j] and | |
| − | + | args[j]['left'] == args[i]['left'] and | |
| − | + | args[j]['to-left'] == args[i]['to-left'] and | |
| − | + | args[j]['oneway-left'] == args[i]['oneway-left'] and | |
| − | + | args[j]['note-left'] == args[i]['note-left'] and | |
| − | + | ( args[j]['through-left'] or args[j]['through'] ) == ( args[i]['through-left'] or args[i]['through'] ) and | |
| − | + | ( args[j]['reverse-left'] or args[j]['reverse'] ) == ( args[i]['reverse-left'] or args[i]['reverse'] ) and | |
| + | fallback ( 'oneway-left', j ) == fallback ( 'oneway-left' ) and | ||
| + | fallback ( 'circular', j ) == fallback ( 'circular' ) and | ||
| + | not args[j]['nonstop'] and | ||
| + | not args[j]['note-row'] do | ||
| + | j = j + 1 | ||
end | end | ||
| − | + | renderSideCell ( | |
| − | + | row, | |
| − | + | j - i, | |
| − | + | stationTitle ( v.left, args, i ), | |
| − | + | yesNo ( fallback ( 'circular' )) and fallback ( 'left terminus' ) or terminus ( 'left' ), | |
| + | yesNo ( v['oneway-left'] or fallback ( 'oneway-left' )), | ||
| + | yesNo ( fallback ( 'circular' )), | ||
| + | ( v['through-left'] or v['through'] ) and dig ( lineData ( i, v['through-left'] or v['through'] ), 'title' ), | ||
| + | yesNo ( v['reverse-left'] or v['reverse'] ), | ||
| + | v['note-left'] | ||
| + | ) | ||
| + | j = j + 1 | ||
| + | end | ||
| + | if i > k - 2 then | ||
| + | while args[k] and | ||
| + | args[k]['line'] == args[i]['line'] and | ||
| + | args[k]['type'] == args[i]['type'] and | ||
| + | args[k]['note-mid'] == args[i]['note-mid'] and | ||
| + | not args[k]['nonstop'] and | ||
| + | not args[k]['note-row'] do | ||
| + | k = k + 1 | ||
end | end | ||
| + | renderMidCells ( | ||
| + | row, | ||
| + | k - i, | ||
| + | fallback ( 'color' ), | ||
| + | fallback ( 'background color' ), | ||
| + | lineData ( i )['title'] or ( string.gsub ( dig ( defaultData ( i ), 'title' ), '%%1', v.line )), | ||
| + | typeData ( i ) and typeData ( i )['title'], | ||
| + | v['note-mid'] or lineData ( i )['note-mid'], | ||
| + | stationTitle ( v.transfer, args, i ) | ||
| + | ) | ||
| + | k = k + 1 | ||
| + | end | ||
| + | if i > l - 2 then | ||
| + | while args[l] and | ||
| + | args[l]['right'] == args[i]['right'] and | ||
| + | args[l]['to-right'] == args[i]['to-right'] and | ||
| + | args[l]['oneway-right'] == args[i]['oneway-right'] and | ||
| + | args[l]['note-right'] == args[i]['note-right'] and | ||
| + | ( args[l]['through-right'] or args[l]['through'] ) == ( args[i]['through-right'] or args[i]['through'] ) and | ||
| + | ( args[l]['reverse-right'] or args[l]['reverse'] ) == ( args[i]['reverse-right'] or args[i]['reverse'] ) and | ||
| + | fallback ( 'oneway-right', l ) == fallback ( 'oneway-right' ) and | ||
| + | fallback ( 'circular', l ) == fallback ( 'circular' ) and | ||
| + | not args[l]['nonstop'] and | ||
| + | not args[l]['note-row'] do | ||
| + | l = l + 1 | ||
| + | end | ||
| + | renderSideCell ( | ||
| + | row, | ||
| + | l - i, | ||
| + | stationTitle ( v.right, args, i ), | ||
| + | yesNo ( fallback ( 'circular' )) and fallback ( 'right terminus' ) or terminus ( 'right' ), | ||
| + | yesNo ( v['oneway-right'] or fallback ( 'oneway-right' )), | ||
| + | yesNo ( fallback ( 'circular' )), | ||
| + | ( v['through-right'] or v['through'] ) and dig ( lineData ( i, v['through-right'] or v['through'] ), 'title' ), | ||
| + | yesNo ( v['reverse-right'] or v['reverse'] ), | ||
| + | v['note-right'] | ||
| + | ) | ||
| + | l = l + 1 | ||
end | end | ||
end | end | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| + | if v['note-row'] then renderNoteRow ( v['note-row'] ) end | ||
end | end | ||
| − | + | return root | |
| − | return | ||
| − | |||
| − | |||
| − | |||
| − | |||
| − | |||
end | end | ||
| − | |||
function p.convert(frame) | function p.convert(frame) | ||
local args = frame.args | local args = frame.args | ||
| Line 901: | Line 738: | ||
return t[1]..code..t[2] | return t[1]..code..t[2] | ||
end | end | ||
| − | |||
return p | return p | ||
Revision as of 16:33, 19 March 2019
Template:Sidebar Adjacent stations
| 30px | This module depends on the following other modules: |
| 40px | This Lua module is used on approximately 47,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages. Consider discussing changes on the talk page before implementing them.
Transclusion count updated automatically (see documentation). |
| 40x40px | 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 module implements {{Adjacent stations}}, {{Rail icon}}, {{Rail color box}}, {{Line link}}, {{Station link}} and {{Rail color}}. Please see those templates' pages for documentation on how to use those templates. (Instructions for the convert function of this module are in the {{Adjacent stations}} documentation.)
The aforementioned templates rely on data stored in subpages for this module (list). For example, {{Rail icon}} generates Template:Rail icon using Module:Adjacent stations/MTR.
It is possible to create and edit data by following existing examples, but having some knowledge of Lua helps prevent mistakes. If you have programmed or used Lua before, you may like to skip the next subsection.
Contents
Terms
- Lua has data types. The ones relevant here are boolean, string, number, and table.
- A boolean is either
trueorfalse. - A string is text, stored as a list of characters. While Lua has several ways of indicating strings within code, in the Lua examples here, strings are indicated by enclosing text in double quotes (e.g.
"This is a string"). - A number is a numerical value, like
0.5or42. - A table is a structure that can contain other objects, including other tables.
- An empty table looks like
{}in the code. - Tables have keys and values, which are typically of the structure
["key"] = value; each key–value pair is separated by a comma. All keys used here are strings or numbers. {"text", "more text"}is equivalent to{[1] = "text", [2] = "more text"}.
- An empty table looks like
- A boolean is either
- A variable can be defined using
local variable_name = "value". - Whitespace is any tab, line break or other space. Whitespace doesn't matter in Lua, but all examples here except for those inline with text are neatly indented for readability, with separate table keys on separate lines.
- A return statement (e.g.
return variable_name) causes a function to exit and reports the value ofvariable_name. The "function" here is the code in the main module calling the subpage, and thevariable_nameshould be the data table.
Basic structure
Two modules are demonstrated below:
| Blank | local p = {
["system title"] = "",
["system icon"] = "",
["station format"] = {
"",
[""] = "",
},
["lines"] = {
[""] = {
["title"] = "",
["color"] = "",
["left terminus"] = "",
["right terminus"] = "",
},
},
}
return p
|
| Example | local x = "%1 light rail station"
local p = {
["system title"] = "[[Kaohsiung Rapid Transit]]",
["system icon"] = "[[File:Kaohsiung Mass Rapid Transit Logo(Logo Only).svg|18px|link=Kaohsiung Rapid Transit]]",
["station format"] = {
"%1 metro station",
["Central Park"] = "Central Park metro station (Taiwan)",
["Ciaotou station"] = "Qiaotou station",
["Kaohsiung Main Station"] = "%1",
["Zuoying"] = "%1 HSR station",
-- Circular light rail
["Lizihnei"] = x,
["Kaisyuan Rueitian"] = x,
["Cianjhen Star"] = x,
["Kaisyuan Jhonghua"] = x,
["Dream Mall"] = x,
["Commerce and Trade Park"] = x,
["Software Technology Park"] = x,
["Kaohsiung Exhibition Center"] = x,
["Cruise Terminal"] = x,
["Glory Pier"] = x,
["Love Pier"] = x,
["Dayi Pier-2"] = x,
["Penglai Pier-2"] = x,
["Hamasen"] = x
},
["lines"] = {
["R"] = {
["title"] = "[[Red line (Kaohsiung MRT)|Red line]]",
["color"] = "d30547",
["left terminus"] = "Gangshan South",
["right terminus"] = "Siaogang"
},
["O"] = {
["title"] = "[[Orange line (Kaohsiung MRT)|Orange line]]",
["color"] = "f77f00",
["left terminus"] = "Sizihwan",
["right terminus"] = "Daliao"
},
["C"] = {
["title"] = "[[Circular light rail]]",
["color"] = "77c35e",
["left terminus"] = "Lizihnei",
["right terminus"] = "Hamasen"
}
},
["aliases"] = {
["red"] = "R",
["orange"] = "O",
["circular"] = "C"
}
}
return p
|
The example module is Module:Adjacent stations/Kaohsiung Rapid Transit.
- The two required table entries are "station format" and "lines". The former is a table with data to form links to station articles, and the latter is a table containing a table for each line.
- "system title" is the text in the middle cell of the table header row.
- "station format" defines the default name format for station articles and exceptions. The first variable ("%1 metro station") is the default. Exceptions are listed as key–value pairs (e.g. "Zuoying"–"Zuoying HSR station"), where the key is the input name. The module displays the input name and links to the article with the formatted name, replacing "%1" with the input. Alternatively, the full wikilink and be entered. This can be used to have the display be different from the input.
- "lines" is where the lines are listed. The names here are used internally and not displayed, so choose a concise one.
- "line title" is the text displayed in the middle of each row indicating the line; "left terminus" is the default station name for the left side terminus, and "right terminus" is the default station name for the right side terminus.
- Each "color" entry is the colour of the line.
Below is Module:Adjacent stations/Taiwan High Speed Rail:
local x = "%1 station"
local p = {
["system title"] = "[[Taiwan High Speed Rail]]",
["system icon"] = "[[File:Taiwan High Speed Rail Logo(Log Only).svg|18px|link=Taiwan High Speed Rail|alt=Taiwan High Speed Rail]]",
["system color"] = "c35617",
["name format"] = "color: #FFFFFF; background-color: #C35617;",
["station format"] = {
"%1 HSR station",
["Taipei"] = "Taipei Main Station",
["Nangang"] = x,
["Banqiao"] = x
},
["lines"] = {
["_default"] = {
["title"] = "[[Taiwan High Speed Rail|THSR]]",
["color"] = "c35617",
["left terminus"] = "Nangang",
["right terminus"] = "Zuoying"
}
}
}
return p
- x (defined in the first line) is a string used for formatting the station name. The variable x is used inside the "station format" table for the three articles where the title ends in "station" instead of "HSR station". This practice is optional but helpful when many articles fit a second pattern.
- The module recognises a virtual line named
["_default"]. The title and colour of this line is used for all lines unless overridden. Parameters are used in the absence of a specifiedline=in transclusion.
Hierarchy and list of parameters
- The first layer of the table is data for the entire system, as well as output options.
- Under the system table is the list of lines.
- The third layer is data for a given line.
- Each line can have 'types'. This can be either types of services or branches of the line.
- The fifth layer is data for a given type.
If not specified, all keys and values are strings.
Main layer (1)
| Parameter | Type | Used in {{Adjacent stations}} | Description |
|---|---|---|---|
["lang"]
|
String | Yes | Values are "en-US" and "en-GB". If not set, "en-GB" is assumed.
|
["system title"]
|
String | Yes | Text in the middle cell of the header. |
["system icon"]
|
String | Yes | Image used in the middle cell of the {{Adjacent stations}} header and by {{Rail icon}}. |
["system icon format"]
|
String | No | Icon type, used by {{Rail icon}}. If specified and not "image", the value is passed to the function that implements {{Rail color box}}.
|
["system color"]
|
String | No | RGB hex triplet (three or six characters, like "BE2D2C" or "039"). Can be called by using only one parameter in {{Rail color}}.
|
["header stop noun"]
|
String | Yes | The noun after 'preceding' and 'following' in the left and right header cells. Default value is "station".
|
["name format"]
|
String | No | CSS for the header of {{Infobox station}} and anything else using the style function with |1=header. Values can be strings or nested tables, with the first level being for the line (whatever's in |style2= of {{Infobox station}}). The second level is currently unused. The first entry in a nested table with no key (i.e. with key 1) is the default.
|
["header background color"]
|
String | No | RGB hex triplet for {{Infobox station}} subheaders and anything else using the style function with |1=subheader. By default, it is a light gray. Values can be strings or nested tables, like those for "name format".
|
["header text color"]
|
String | No | RGB hex triplet for {{Infobox station}} subheaders and anything else using the style function with |1=subheader. By default, it is calculated based on the header background color. Values can be strings or nested tables, like those for ["name format"].
|
["station format"]
|
Table or string | Yes | Table containing station format strings. The first entry without a specified key (i.e. with the key being the number 1) is the default, and all other entries must have keys corresponding to the input. Format strings without wikilink brackets are converted to links, with the input (usually the station name) used as the displayed text. Tables can be nested within this table to indicate options based on the line and line type passed to this template.
|
["lines"]
|
Table | Yes | Data table containing line tables. |
["aliases"]
|
Table | Yes | Table containing aliases (as table keys) for lines (as values). All keys are lowercase, as the input is treated as case-insensitive by being lower-cased. |
Station format table (2)
| Parameter | Type | Used in {{Adjacent stations}} | Description |
|---|---|---|---|
[1]
|
String | Yes | Default format. |
["non-default station name"]
|
String or table | Yes | Format for a non-default station, or line-specific format table. |
Line-specific format table (3)
| Parameter | Type | Used in {{Adjacent stations}} | Description |
|---|---|---|---|
[1]
|
String | Yes | Default format. |
["line name"]
|
String or table | Yes | Format for a non-default station, or type-specific format table. |
Type-specific format table (4)
| Parameter | Type | Used in {{Adjacent stations}} | Description |
|---|---|---|---|
[1]
|
String | Yes | Default format. |
["type name"]
|
String | Yes | Format for a non-default station. |
Line table (3)
A virtual line named ["_default"] can be added to set default values for all lines. Currently, this is available for two parameters.
| Parameter | Type | Used in {{Adjacent stations}} | Description |
|---|---|---|---|
["title"]
|
String | Yes | The text displayed in the middle cell, typically a link to the line's article. If not specified, then the data in ["_default"] is used (%1 in the default value is replaced by the input after alias replacement).
|
["short name"]
|
String | No | Abbreviated line name used by {{Rail color box}}. |
["icon"]
|
String | No | Image used by {{Rail icon}}. |
["icon format"]
|
String | No | Icon type used by {{Rail icon}}. If specified and not "image", the value is passed to the function that implements {{Rail color box}}.
|
["color"]
|
String | Yes | RGB hex triplet. Lines fall back to the ["_default"] colour (if any) or the system's colour if they themselves do not have one; types fall back to the line's colour (if any), to the ["_default"] colour (if any) or to the system's colour. This colour is used in the second and fourth columns of {{Adjacent stations}}, and by {{Rail color box}} and {{Rail icon}} as the emphasised colour. By default, if a type and its line both have a colour, then the line's colour will be treated as the background colour (see next section) for the line name in the middle cell. This can be turned off by setting the type's background colour to "" or "transparent".
|
["background color"]
|
String | Yes | RGB hex triplet (three or six characters). This colour is optional and is only displayed behind the line name in the middle cell. The module adds transparency so that all text displayed over the background is legible. |
["border color"]
|
String | No | RGB hex triplet used by {{Rail color box}}. |
["text color"]
|
String | No | RGB hex triplet used by {{Rail color box}}. |
["left terminus"]
|
String | Yes | The station which is usually the left terminus of the line. If there are multiple stations by default, the value should be a table containing numbered values (e.g. ["left terminus"] = {"Chesham", "Amersham"}). The key ["via"] in that table can be used to append 'via' and the value's station link.
|
["right terminus"]
|
String | Yes | The station which is usually the right terminus of the line; behaves like ["left terminus"].
|
["note-mid"]
|
String | Yes | Default small text below line and type names. Overridden by |note-mid= in transclusion.
|
["circular"]
|
Boolean | Yes | If the value is true then the termini will display without 'toward'/'towards'.
|
["oneway-left"]
|
Boolean | Yes | If the value is true then 'One-way operation' will display instead of the left terminus.
|
["oneway-right"]
|
Boolean | Yes | Right counterpart of oneway-left. |
["types"]
|
Table | Yes | Table containing the line type tables. |
Type table (5)
| Parameter | Type | Used in {{Adjacent stations}} | Description |
|---|---|---|---|
["title"]
|
String | Yes | The name of the line type. In {{Adjacent stations}}, this is displayed as normal-sized text below the line name in the middle cell; in {{Rail color box}}, for some options this is displayed after the line name, separated from it by a spaced en dash (this is also used for the nonstop text). To avoid displaying a type name, set this to "".
|
["short name"]
|
String | No | Abbreviated line name used by {{Rail color box}}. |
["icon"]
|
String | No | Image used by {{Rail icon}}. |
["icon format"]
|
String | No | Icon type used by {{Rail icon}}. If specified and not "image", the value is passed to the function that implements {{Rail color box}}.
|
["color"]
|
String | Yes | RGB hex triplet. Lines fall back to the ["_default"] colour (if any) or the system's colour if they themselves do not have one; types fall back to the line's colour (if any), to the ["_default"] colour (if any) or to the system's colour. This colour is used in the second and fourth columns of {{Adjacent stations}}, and by {{Rail color box}} and {{Rail icon}} as the emphasised colour. By default, if a type and its line both have a colour, then the line's colour will be treated as the background colour (see next section) for the line name in the middle cell. This can be turned off by setting the type's background colour to "" or "transparent".
|
["background color"]
|
String | Yes | RGB hex triplet (three or six characters). This colour is optional and is only displayed behind the line name in the middle cell. The module adds transparency so that all text displayed over the background is legible. |
["border color"]
|
String | No | RGB hex triplet used by {{Rail color box}}. |
["text color"]
|
String | No | RGB hex triplet used by {{Rail color box}}. |
["left terminus"]
|
String | Yes | The station which is usually the left terminus of the line. Overrides line terminus. If there are multiple stations by default, the value should be a table containing numbered values (e.g. ["left terminus"] = {"Chesham", "Amersham"}). The key ["via"] in that table can be used to append 'via' and the value's station link.
|
["right terminus"]
|
String | Yes | The station which is usually the right terminus of the line; behaves like ["left terminus"].
|
["note-mid"]
|
String | Yes | Default small text below line and type names. Overridden by |note-mid= in transclusion.
|
For developers
Suggestions are welcomed on the talk page.
To-do list
- Convert more systems from {{S-line}}, {{rail line}}, {{J-rserv}} and {{J-route}}
- Make an example module which contains all of the module's features, to avoid excessive examples in the documentation (maybe based on {{Rdt demo}})
- Allow direct replacement of {{Rail line}}?
- Function for calling a line terminus (for station layouts?)
- Before translation: figure out how to handle grammatical gender and inflection in various languages with the i18n table (e.g. these phrases)
- Allow inline sources to be added
- Figure out Wikidata integration (require sources on Wikidata end)
- Add a short list of changes from {{S-line}}, for the convenience of the many editors who have used it in the last 11 years
- changes in function (new structure, data inside module, circular and branch functionality changed, replacement of manual cell merging…)
- parameter name changes (-left and -right, mostly – search {{S-line}} for {{{, maybe with the TemplateData generator, to make a list)
local p, data, defaultData, lineData, typeData, isFuncAdjacent = {}
local function dig ( ... )
-- Digs through a table with sub-tables using arguments as keys, returning the value of the last key argument
-- Analogous to returning a file given a file path with sub-folders
-- Returns nil if any given sub-table does not exist
local arg, n = { ... }, select ( '#', ... )
local a, i = arg[1], 1
while a and i < n do
a = a[arg[i + 1]]
i = i + 1
end
return a or nil
end
local function makeInvokeFunc ( funcName )
return function ( frame )
local args = require ( 'Module:Arguments' ).getArgs ( frame )
if funcName == '_adjacent' then
isFuncAdjacent = true
local tableTools = require ( 'Module:TableTools' )
args = tableTools.numData ( args )
if args.other then
args[1] = args[1] or {}
for k, _ in pairs ( args.other ) do args[1][k] = args[1][k] or args['other'][k] end
end
return p[funcName]( tableTools.compressSparseArray ( args ))
else
args.system = args.system or args[1]
if args.system then
local s = 'Module:Adjacent stations/' .. args.system
data = mw.title.new ( s ).exists and mw.loadData ( s )
end
if funcName ~= '_infobox' then
args.line = args.line or args[funcName == '_station' and 3 or 2]
if data and args.line then
args.line =
dig ( data, 'lines', args.line ) and args.line or
dig ( data, 'aliases', string.lower ( args.line ))
end
args['type'] = args['type'] or args[funcName == '_station' and 4 or 3]
if funcName ~= '_station' then
defaultData = dig ( data, 'lines', '_default' )
lineData = dig ( data, 'lines', args.line )
typeData = dig ( lineData, 'types', args['type'] )
end
end
return p[funcName]( args, frame )
end
end
end
p.infobox = makeInvokeFunc ( '_infobox' )
function p._infobox ( args, frame )
local data = dig ( data, 'infobox station') or data
if args[3] == 'header' then return
dig ( data, 'header', args[2] or 1) or
dig ( data, 'name format', args[2] or 1) or
(args[2] or args.system) and frame:expandTemplate {
title = ( args[2] or args.system ) .. ' style',
args = { 'name_format' }
}
elseif args[3] == 'sub-header' then
if dig ( data, 'sub-header') then
return dig ( data, 'sub-header', args[2] or 1)
else
local t = {}
t[1] = 'background:'
t[2] =
dig ( data, 'header background color', args[2] or 1) or
(args[2] or args.system) and frame:expandTemplate {
title = ( args[2] or args.system ) .. ' style',
args = { 'thbgcolor' }
} or
'#EFEFEF'
t[2] = string.match ( t[2], '#') and t[2] or '#' .. t[2]
t[3] = ';color:'
t[4] =
dig ( data, 'header text color', args[2] or 1) or
(args[2] or args.system) and frame:expandTemplate {
title = ( args[2] or args.system ) .. ' style',
args = { 'thcolor' }
} or
require ( 'Module:Color contrast' )._greatercontrast ({ t[2] })
t[4] = string.match ( t[4], '#') and t[4] or '#' .. t[4]
return table.concat ( t )
end
end
end
local function stationTitle ( station, args, n )
if station and data then
local data = isFuncAdjacent and data[n] or data
local line = isFuncAdjacent and args[n]['line'] or args['line']
local typ = isFuncAdjacent and args[n]['type'] or args['type']
local link
if type ( data['station format'] ) == 'table' then
local defaultFormat = data['station format']
if type ( defaultFormat[station] ) == 'table' then
local stationFormat = defaultFormat[station]
if line then
line =
stationFormat[line] and line or
dig ( data, 'aliases', string.lower ( line ))
end
if type ( stationFormat[line] ) == 'table' then
local lineFormat = stationFormat[line]
link = lineFormat[typ] or lineFormat[1]
else
link = stationFormat[line] or stationFormat[1]
end
elseif type ( defaultFormat[station] ) == 'number' then
link = defaultFormat[defaultFormat[station]]
else
link = defaultFormat[station] or defaultFormat[1]
end
else
link = data['station format']
end
link = ( string.gsub ( link, '%%1', station ))
return
string.match ( link, '%[%[.-%]%]' ) and link or
table.concat ({'[[', link, '|', station, ']]' })
end
end
p.station = makeInvokeFunc ( '_station' )
function p._station ( args, frame )
args.station = args.station or args[2]
if data then
return stationTitle ( args.station, args )
else
return frame:expandTemplate {
title = args.system and args.system .. ' stations',
args = {
['station'] = args.station,
['line'] = args.line,
['branch'] = args['type']
}
}
end
end
p.color = makeInvokeFunc ( '_color' )
function p._color ( args, frame )
if data then
return mw.text.nowiki (
typeData and typeData['color'] or
lineData and lineData['color'] or
defaultData and defaultData['color']
)
else
return frame:expandTemplate {
title = args.system and args.system .. ' color',
args = { args.line, ['branch'] = args['type'] }
}
end
end
local root = mw.html.create ( 'div' )
local function renderBox ( style, colour, lineName, lineTitle )
if colour then
colour = string.match ( colour, '#' ) and colour or '#' .. colour
end
local box = mw.html.create ( 'span' )
-- Colour settings
if
style == 'dot' or
style == 'ldot' or
style == 'square' or
style == 'lsquare' or
style == 'xroute' then
box:css ( 'color', colour )
else
box:css ( 'background-color', colour )
if style == 'route' or style == 'croute' then
box
:css ( 'color',
typeData and typeData['text color'] or
lineData and lineData['text color'] or
require ( 'Module:Color contrast' )._greatercontrast ({ colour })
)
end
end
-- Border settings
if
style == 'legend' or style == nil or
style == 'linked' or style == 'link' or
style == 'inline' or style == 'yes' or
style == 'box' then
box:css ( 'border', '1px solid black' )
elseif style and string.match ( style, 'route' ) then
box
:css ( 'border', '.075em solid ' .. (
typeData and typeData['border color'] or
lineData and lineData['border color'] or
colour
)
)
if style ~= 'route' then
box:css ( 'border-radius', '.5em' )
end
end
-- Additional style-specific settings
if style == 'legend' or style == nil then
root
:addClass ( 'legend' )
:css ( '-webkit-column-break-inside', 'avoid' )
:css ( 'page-break-inside', 'avoid' )
:css ( 'break-inside', 'avoid-column' )
box
:addClass ( 'legend-color' )
:css ( 'display', 'inline-block' )
:css ( 'width', '1.5em' )
:css ( 'height', '1.5em' )
:css ( 'margin', '1px' )
elseif
style == 'dot' or
style == 'ldot' or
style == 'square' or
style == 'lsquare' then
box:css ( 'line-height', 'initial' )
elseif style and string.match ( style, 'route' ) then
box
:css ( 'font-weight', 'bold' )
:css ( 'font-size', 'inherit' )
:css ( 'white-space', 'nowrap' )
:css ( 'padding', '0 .3em' )
end
-- Text for the span tag
local boxText = {
['inline'] = string.rep ( ' ',4 ), ['yes'] = string.rep ( ' ', 4 ),
['box'] = string.rep ( ' ', 4 ),
['linked'] = string.rep ( ' ', 4 ), ['link'] = string.rep ( ' ', 4 ),
['small'] = string.rep ( ' ', 1 ),
['legend'] = string.rep ( ' ', 1 ),
['dot'] = '●',
['ldot'] = '●',
['square'] = '■',
['lsquare'] = '■',
['route'] = lineName,
['croute'] = lineName,
['xroute'] = lineName
}
box:wikitext ( boxText[style] or string.rep ( ' ', 1 ))
-- Adds link to text
if
style == 'linked' or style == 'link' or
style == 'ldot' or
style == 'lsquare' or
style and string.match ( style, 'route' ) then
if string.match ( lineTitle, '%[%[.-%]%]' ) then
if string.match ( lineTitle, '|' ) then
root:wikitext (( string.gsub ( lineTitle, '%[%[(.-)|.-%]%]', '[[%1|' .. tostring ( box ) .. ']]' )))
else
root:wikitext (( string.gsub ( lineTitle, '%[%[(.-)%]%]', '[[%1|' .. tostring ( box ) .. ']]' )))
end
else
root:wikitext ( tostring ( box ))
end
else
root:wikitext ( tostring ( box ))
end
end
p.line = makeInvokeFunc ( '_line' )
function p._line ( args, frame )
if data then
local s =
typeData and typeData['title'] and table.concat ({ lineData['title'], ' (', typeData['title'], ')' }) or
lineData and lineData['title'] or
defaultData and ( string.gsub ( defaultData['title'], '%%1', args.line or '_default' ))
if args.icon then
if args.icon == 'image' then
args.style = nil
return p._icon ( args ) .. ' ' .. s
elseif
args.icon == 'legend' or
args.icon == 'inline' or
args.icon == 'small' or
args.icon == 'dot' or
args.icon == 'square' then
renderBox ( args.icon, p._color ( args ), args.line, s )
root:wikitext ( ' ', s )
return root
end
else
return s
end
else
return frame:expandTemplate {
title = args.system and args.system .. ' lines',
args = { args.line, ['branch'] = args['type'] }
}
end
end
p.icon = makeInvokeFunc ( '_icon' )
function p._icon ( args, frame )
if data then
local s =
typeData and typeData['icon'] or
lineData and lineData['icon'] or
data and data['system icon']
if
not s or
args.style == 'box' or
args.style == 'linked' or args.style == 'link' or
args.style == 'ldot' or
args.style == 'lsquare' or
args.style and string.match ( args.style, 'route' ) then
renderBox ( args.style or 'inline', p._color ( args ), args.line, p._line ( args ))
return root
else
return s
end
else
return frame:expandTemplate {
title = 'Rail-interchange',
args = { string.lower ( args.system ), string.lower ( args.line ), ['size'] = args.size }
}
end
end
p.box = makeInvokeFunc ( '_box' )
function p._box ( args, frame )
local lineTitle = p._line ( args, frame )
local style =
args.style or args.inline or args[3] or
dig ( typeData, 'icon format' ) or
dig ( lineData, 'icon format' ) or
dig ( data, 'system icon format' )
renderBox ( style, p._color ( args, frame ), args.line, lineTitle )
if
style == 'legend' or style == nil or
style == 'inline' or style == 'yes' or
style == 'small' or
style == 'dot' or
style == 'square' then
root:wikitext ( ' ', lineTitle )
end
return root
end
p.main = makeInvokeFunc ( '_adjacent' )
p.adjacent = makeInvokeFunc ( '_adjacent' )
function p._adjacent ( args )
local yesNo = require ( 'Module:Yesno' )
local i18n = require ( 'Module:Adjacent stations/i18n' )
local root, lang = mw.html.create ( 'table' ), 'en-GB'
root:addClass ( 'wikitable adjacent-stations' )
local function renderHeader ( stopNoun, systemIcon, systemTitle )
root
:tag ( 'tr' )
:tag ( 'th' )
:addClass ( 'hcA' )
:wikitext ( i18n[lang]['preceding']( stopNoun ))
:done ()
:tag ( 'th' )
:attr ( 'colspan', 3 )
:css ( 'vertical-align', 'middle' )
:wikitext (
systemIcon and systemTitle and systemIcon .. ' ' .. systemTitle or
systemTitle or
systemIcon
)
:done ()
:tag ( 'th' )
:addClass ( 'hcA' )
:wikitext ( i18n[lang]['following']( stopNoun ))
end
local function renderSubHeader ( subHeader )
root
:tag ( 'tr' )
:tag ( 'th' )
:attr ( 'colspan', 5 )
:addClass ( 'hmA' )
:wikitext ( subHeader )
end
local function renderSideCell ( row, rowSpan, adjacent, terminus, oneWay, circular, through, Reverse, note )
local mainText, subText = mw.html.create ( 'div' )
if adjacent then
mainText:wikitext ( adjacent )
subText = mw.html.create ( 'div' )
subText:addClass ( 'isA' )
if adjacent == terminus then
subText:wikitext ( 'Terminus' )
else
subText:wikitext ( oneWay and 'one-way operation' or circular and terminus or i18n[lang]['towards']( terminus ))
end
else
mainText:css ( 'font-style', 'italic' )
mainText:wikitext ( Reverse and 'Reverses direction' or through and i18n[lang]['through']( through ) or 'Terminus' )
end
row
:tag ( 'td' )
:attr ( 'rowspan', rowSpan )
:addClass ( 'bcA' )
:node ( mainText )
:tag ( 'div' )
:css ( 'font-size', 'smaller' )
:wikitext ( note )
:done ()
:node ( subText )
end
local function renderMidCells ( row, rowSpan, colour, backgroundColour, lineTitle, typeTitle, note, transfer )
if colour then
colour = string.match ( colour, '#' ) and colour or '#' .. colour
end
row
:tag ( 'td' )
:attr ( 'rowspan', rowSpan )
:addClass ( 'bbA' )
:css ( 'background-color', colour )
:done ()
:tag ( 'td' )
:attr ( 'rowspan', rowSpan )
:addClass ( 'bcA' )
:css ( 'background-color', backgroundColour )
:wikitext ( lineTitle )
:tag ( 'div' )
:wikitext ( typeTitle )
:done ()
:tag ( 'div' )
:css ( 'font-size', 'smaller' )
:wikitext ( note )
:done ()
:tag ( 'div' )
:addClass ( 'isA' )
:wikitext ( i18n[lang]['transfer']( transfer ))
:done ()
:done ()
:tag ( 'td' )
:attr ( 'rowspan', rowSpan )
:addClass ( 'bbA' )
:css ( 'background-color', colour )
end
local function renderNonStopRow ( title, colour, isFormer )
if colour then
colour = string.match ( colour, '#' ) and colour or '#' .. colour
end
root
:tag ( 'tr' )
:tag ( 'td' )
:attr ( 'colspan', 5 )
:addClass ( 'bcA' )
:tag ( 'div' )
:tag ( 'span' )
:css ( 'border', '1px solid black' )
:css ( 'background-color', colour )
:wikitext ( string.rep ( ' ', 4 ))
:done ()
:wikitext ( ' ', isFormer == true and i18n[lang]['nonstop_past']( title ) or i18n[lang]['nonstop_present']( title ))
end
local function renderNoteRow ( note )
root
:tag ( 'tr' )
:tag ( 'td' )
:attr ( 'colspan', 5 )
:addClass ( 'bcA' )
:wikitext ( note )
end
local function makeTerminusFunc ( n, fallback )
return function ( side )
local termini = fallback ( side .. ' terminus' )
if type ( termini ) == 'string' then
return stationTitle ( termini, args, n )
elseif type ( termini ) == 'table' then
local i, t, to = 1, {}, args[n]['to-' .. side] or args[n]['to']
while termini[i] and to ~= termini[i] do
t[i] = stationTitle ( termini[i], args, n )
i = i + 1
end
local via = stationTitle ( termini['via'], args, n )
return
stationTitle ( termini[i], args, n ) or
via and mw.text.listToText ( t, nil, ' or ' ) .. ' via ' .. via or
mw.text.listToText ( t, nil, ' or ' )
end
end
end
data = {}
local j, k, l = 2, 2, 2
for i, v in ipairs ( args ) do
if v.header then renderSubHeader ( v.header ) end
args[i]['system'] = args[i]['system'] or i > 1 and args[i - 1]['system']
if args[i]['system'] then
data[i] = mw.loadData ( 'Module:Adjacent stations/' .. args[i]['system'] )
lang = dig ( data[i], 'lang' ) or 'en-GB'
defaultData = function ( n ) return dig ( data[n], 'lines', '_default' ) end
if args[i]['line'] then
args[i]['line'] =
dig ( data[i], 'lines', args[i]['line'] ) and args[i]['line'] or
dig ( data[i], 'aliases', string.lower ( args[i]['line'] )) or
error ( i18n[lang]['error_unknown']( args[i]['line'] ))
else
args[i]['line'] = i == 1 and '_default' or args[i - 1]['line']
end
lineData = function ( n, line ) return
dig ( data[n], 'lines', line or v.line ) or
dig ( data[n], 'lines', dig ( data[n], 'aliases', string.lower ( line or v.line )))
end
typeData = function ( n ) return dig ( lineData ( n ), 'types', v['type'] ) end
local function fallback ( parameter, n )
return dig ( typeData ( n or i ), parameter ) or dig ( lineData ( n or i ), parameter ) or dig ( defaultData ( n or i ), parameter )
end
local terminus = makeTerminusFunc ( i, fallback )
if i == 1 or args[i]['system'] ~= args[i - 1]['system'] then
renderHeader (
data[i]['header stop noun'] or i18n[lang]['stop_noun'],
data[i]['system icon'],
data[i]['system title']
)
end
if v.nonstop then
renderNonStopRow ( fallback ( 'title' ), fallback ( 'color' ), v.nonstop == 'former' )
else
local row = root:tag ( 'tr' )
if i > j - 2 then
while args[j] and
args[j]['left'] == args[i]['left'] and
args[j]['to-left'] == args[i]['to-left'] and
args[j]['oneway-left'] == args[i]['oneway-left'] and
args[j]['note-left'] == args[i]['note-left'] and
( args[j]['through-left'] or args[j]['through'] ) == ( args[i]['through-left'] or args[i]['through'] ) and
( args[j]['reverse-left'] or args[j]['reverse'] ) == ( args[i]['reverse-left'] or args[i]['reverse'] ) and
fallback ( 'oneway-left', j ) == fallback ( 'oneway-left' ) and
fallback ( 'circular', j ) == fallback ( 'circular' ) and
not args[j]['nonstop'] and
not args[j]['note-row'] do
j = j + 1
end
renderSideCell (
row,
j - i,
stationTitle ( v.left, args, i ),
yesNo ( fallback ( 'circular' )) and fallback ( 'left terminus' ) or terminus ( 'left' ),
yesNo ( v['oneway-left'] or fallback ( 'oneway-left' )),
yesNo ( fallback ( 'circular' )),
( v['through-left'] or v['through'] ) and dig ( lineData ( i, v['through-left'] or v['through'] ), 'title' ),
yesNo ( v['reverse-left'] or v['reverse'] ),
v['note-left']
)
j = j + 1
end
if i > k - 2 then
while args[k] and
args[k]['line'] == args[i]['line'] and
args[k]['type'] == args[i]['type'] and
args[k]['note-mid'] == args[i]['note-mid'] and
not args[k]['nonstop'] and
not args[k]['note-row'] do
k = k + 1
end
renderMidCells (
row,
k - i,
fallback ( 'color' ),
fallback ( 'background color' ),
lineData ( i )['title'] or ( string.gsub ( dig ( defaultData ( i ), 'title' ), '%%1', v.line )),
typeData ( i ) and typeData ( i )['title'],
v['note-mid'] or lineData ( i )['note-mid'],
stationTitle ( v.transfer, args, i )
)
k = k + 1
end
if i > l - 2 then
while args[l] and
args[l]['right'] == args[i]['right'] and
args[l]['to-right'] == args[i]['to-right'] and
args[l]['oneway-right'] == args[i]['oneway-right'] and
args[l]['note-right'] == args[i]['note-right'] and
( args[l]['through-right'] or args[l]['through'] ) == ( args[i]['through-right'] or args[i]['through'] ) and
( args[l]['reverse-right'] or args[l]['reverse'] ) == ( args[i]['reverse-right'] or args[i]['reverse'] ) and
fallback ( 'oneway-right', l ) == fallback ( 'oneway-right' ) and
fallback ( 'circular', l ) == fallback ( 'circular' ) and
not args[l]['nonstop'] and
not args[l]['note-row'] do
l = l + 1
end
renderSideCell (
row,
l - i,
stationTitle ( v.right, args, i ),
yesNo ( fallback ( 'circular' )) and fallback ( 'right terminus' ) or terminus ( 'right' ),
yesNo ( v['oneway-right'] or fallback ( 'oneway-right' )),
yesNo ( fallback ( 'circular' )),
( v['through-right'] or v['through'] ) and dig ( lineData ( i, v['through-right'] or v['through'] ), 'title' ),
yesNo ( v['reverse-right'] or v['reverse'] ),
v['note-right']
)
l = l + 1
end
end
end
if v['note-row'] then renderNoteRow ( v['note-row'] ) end
end
return root
end
function p.convert(frame)
local args = frame.args
local code = mw.text.split(mw.ustring.gsub(args[1], '^%s*{{(.*)}}%s*$', '%1'), '%s*}}%s*{{%s*')
local system
local group = 0
local delete = {
['s-rail'] = true,
['s-rail-next'] = true,
['s-rail-national'] = true,
['s-start'] = true,
['s-rail-start'] = true,
['start'] = true,
['s-end'] = true,
['end'] = true
}
local order = {
'line', 'left', 'right', 'to-left', 'to-right',
'oneway-left', 'oneway-right', 'through-left', 'through-right',
'reverse', 'reverse-left', 'reverse-right',
'note-left', 'note-mid', 'note-right', 'transfer'
-- circular: use module subpage
-- state: not implemented
}
local replace = {
['previous'] = 'left',
['next'] = 'right',
['type'] = 'to-left',
['type2'] = 'to-right',
['branch'] = 'type',
['note'] = 'note-left',
['notemid'] = 'note-mid',
['note2'] = 'note-right',
['oneway1'] = 'oneway-left',
['oneway2'] = 'oneway-right',
['through1'] = 'through-left',
['through2'] = 'through-right'
}
local remove_rows = {}
local data = {}
for i, v in ipairs(code) do
code[i] = mw.ustring.gsub(code[i], '\n', ' ')
local template = mw.ustring.lower(mw.text.trim(mw.ustring.match(code[i], '^[^|]+')))
code[i] = mw.ustring.match(code[i], '(|.+)$')
if template == 's-line' then
data[i] = {}
local this_system = mw.text.trim(mw.ustring.match(code[i], '|%s*system%s*=([^|]+)'))
code[i] = mw.text.split(code[i], '%s*|%s*')
for m, n in ipairs(code[i]) do
local tmp = mw.text.split(n, '%s*=%s*')
if tmp[3] then
tmp[2] = mw.ustring.gsub(n, '^.-%s*=', '')
end
tmp[1] = replace[tmp[1]] or tmp[1]
if tmp[2] then
-- checks for matching brackets
local curly = select(2, mw.ustring.gsub(tmp[2], "{", ""))-select(2, mw.ustring.gsub(tmp[2], "}", ""))
local square = select(2, mw.ustring.gsub(tmp[2], "%[", ""))-select(2, mw.ustring.gsub(tmp[2], "%]", ""))
if not (curly == 0 and square == 0) then
local count = mw.clone(m)+1
while not (curly == 0 and square == 0) do
tmp[2] = tmp[2]..'|'..code[i][count]
curly = curly+select(2, mw.ustring.gsub(code[i][count], "{", ""))-select(2, mw.ustring.gsub(code[i][count], "}", ""))
square = square+select(2, mw.ustring.gsub(code[i][count], "%[", ""))-select(2, mw.ustring.gsub(code[i][count], "%]", ""))
code[i][count] = ''
count = count+1
end
end
data[i][tmp[1]] = tmp[2]
end
end
if (this_system ~= system) or (not system) then
system = this_system
data[i]['system'] = system
else
data[i]['system'] = nil
end
local last = data[i-1] or data[i-2] or data[i-3]
if last then
for r, s in pairs({
['hide1'] = {'left', 'to-left', 'note-left', 'oneway-left'},
['hide2'] = {'right', 'to-right', 'note-right', 'oneway-right'},
['hidemid'] = {'type', 'note-mid'}
}) do
if data[i][r] then
for m, n in ipairs(s) do
if not data[i][n] then
data[i][n] = last[n]
end
end
end
end
end
code[i] = {}
local X = '|'
local Y = (i+group)..'='
if data[i]['system'] then
table.insert(code[i], '|system')
table.insert(code[i], Y)
table.insert(code[i], data[i]['system'])
table.insert(code[i], '\n')
end
for m, n in ipairs(order) do
if data[i][n] then
table.insert(code[i], X)
table.insert(code[i], n)
table.insert(code[i], Y)
table.insert(code[i], data[i][n])
end
end
code[i] = table.concat(code[i])
elseif template == 's-note' then
code[i] = mw.ustring.gsub(code[i], '|%s*text%s*=', '|header'..i+group..'=')
code[i] = mw.ustring.gsub(code[i], '|%s*wide%s*=[^|]*', '')
elseif template == 's-text' then
code[i] = mw.ustring.gsub(code[i], '|%s*text%s*=', '|note-row'..i+group..'=')
elseif delete[template] then
code[i] = ''
table.insert(remove_rows, 1, i) -- at the start, so that the rows are deleted in reverse order
group = group-1
end
end
for i, v in ipairs(remove_rows) do
table.remove(code, v)
end
code = table.concat(code, '\n')
local t = {'{{Adjacent stations', '\n}}'}
system = mw.ustring.match(code, '|system(%d*)=')
code = mw.ustring.gsub(code, '\n\n+', '\n')
if tonumber(system) > 1 then
-- If s-line isn't the first template then the system will have to be moved to the top
system = mw.ustring.match(code, '|system%d*=([^|]*[^|\n])')
code = mw.ustring.gsub(code, '|system%d*=[^|]*', '')
code = '\n|system1='..system..code
elseif not mw.ustring.match(code, '^[^{%[]*|[^=|]+2=') then
-- If there's only one parameter group then there's no need to have line breaks
code = mw.ustring.gsub(code, '\n', '')
code = mw.ustring.gsub(code, '(|[^=|]+)1=', '%1=')
t[2] = '}}'
if not mw.ustring.match(code, '[%[{]') then
code = mw.ustring.gsub(code, '|[^=|]*=$', '')
code = mw.ustring.gsub(code, '|[^=|]*$', '')
end
end
if not mw.ustring.match(code, '[%[{]') then
code = mw.ustring.gsub(code, '|[^=|]*=|', '|')
code = mw.ustring.gsub(code, '|[^=|]*|', '|')
code = mw.ustring.gsub(code, '|[^=|]*=\n', '\n')
code = mw.ustring.gsub(code, '|[^=|]*\n', '\n')
end
return t[1]..code..t[2]
end
return p