Module:Adjacent stations: Difference between revisions

Content deleted Content added
Undid revision 879624096 by Ythlev (talk)
fix text color in dark mode; this generally works but may cause problems, in which case revert or try specifying a different CSS value. Some of these icons and boxes don't even have text, but the Linter complains, making it difficult to find actual problems amid the noise.
 
(52 intermediate revisions by 20 users not shown)
Line 1:
require('Module:No globalsstrict')
 
local p = {}
Line 20:
-- • Remove any unnecessary translations.
 
local i18n = {require("Module:Adjacent stations/i18n")
['en-GB'] = {
-- ['word_space'] = ' ',
['preceding'] = function(var)
return 'Preceding ' .. var
end,
['following'] = function(var)
return 'Following ' .. var
end,
['stop_noun'] = 'station',
['nonstop_past'] = function(var)
return var .. ' did not stop here'
end,
['nonstop_present'] = function(var)
return var .. ' does not stop here'
end,
['comma'] = function(var)
return ', ' .. var
end,
['or'] = function(var)
return ' or ' .. var
end,
['via-first'] = false, -- If the «via» text comes before termini, change to «true»
['via'] = function(var)
return ' via ' .. var
end,
['comma-format'] = ',%s+',
['or-format'] = '%s+or%s+',
['via-format'] = '%s+via%s+(.+)$', -- first match is station name
['towards'] = function(var)
return 'towards ' .. var
end,
['through'] = function(var)
return 'through to ' .. var
end,
['reverse'] = 'Reverses direction',
['oneway'] = 'One-way operation',
['terminus'] = 'Terminus',
['error_duplicate'] = function(var)
return 'Same row number used multiple times for ' .. var
end,
['error_format'] = 'Station format table missing in data page',
['error_line'] = 'Lines table missing in data module',
['error_missing'] = function(var)
return '"' .. (var or '') .. '" is missing from the data page'
end,
['error_unknown'] = function(var)
return 'Unknown system or line "' .. (var or '') .. '"'
end
},
['en-US'] = {
-- ['word_space'] = ' ',
['preceding'] = function(var)
return 'Preceding ' .. var
end,
['following'] = function(var)
return 'Following ' .. var
end,
['stop_noun'] = 'station',
['nonstop_past'] = function(var)
return var .. ' did not stop here'
end,
['nonstop_present'] = function(var)
return var .. ' does not stop here'
end,
['comma'] = function(var)
return ', ' .. var
end,
['or'] = function(var)
return ' or ' .. var
end,
['via-first'] = false, -- If the «via» text comes before termini, change to «true»
['via'] = function(var)
return ' via ' .. var
end,
['comma-format'] = ',%s+',
['or-format'] = '%s+or%s+',
['via-format'] = '%s+via%s+(.+)$', -- first match is station name
['towards'] = function(var)
return 'toward ' .. var
end,
['through'] = function(var)
return 'through to ' .. var
end,
['reverse'] = 'Reverses direction',
['oneway'] = 'One-way operation',
['terminus'] = 'Terminus',
['error_duplicate'] = function(var)
return 'Same row number used multiple times for ' .. var
end,
['error_format'] = 'Station format table missing in data module',
['error_line'] = 'Lines table missing in data module',
['error_missing'] = function(var)
return '"' .. (var or '') .. '" is missing from the data page'
end,
['error_unknown'] = function(var)
return 'Unknown system or line "' .. (var or '') .. '"'
end
}
}
 
local require = require
 
local function getData(system, verify)
if verify then
Line 132 ⟶ 30:
)
end
 
local lower = mw.ustring.lower
local gsub = mw.ustring.gsub
 
local function getLine(data, lineN)
if lineN then
if data['aliases'] then
lineN = data['aliases'][mw.ustring.lower(lineN)] or lineN
end
local default = data['lines']['_default'] or {}
Line 146 ⟶ 41:
if v then line[k] = line[k] or v end
end
line['title'] = line['title'] and mw.ustring.gsub(line['title'], '%%1', lineN)
return line, lineN
end
Line 170 ⟶ 65:
end
 
local match = mw.ustring.match
local concat = table.concat
local lineN, typeN
 
local function somethingMissing(name, key, formats)
local formatKeys = {}
for k in pairs(formats) do
table.insert(formatKeys, k)
end
return name .. ' was "' .. key .. '" but neither an entry for it nor a default was found. Choices were: ' .. table.concat(formatKeys, ', ')
end
 
local function getStation(station, _Format)
if type(_Format) == 'table' then
_Formatlocal lineNformats = _Format[lineN] or _Format[1]
if type(_Format) == 'table'lineNformats[lineN] or thenlineNformats[1]
_Formatif =not _Format[typeN] or _Format[1]then
error(somethingMissing('lineN', lineN, lineNformats))
elseif type(_Format) == 'table' then
local typeNformats = _Format
_Format = typeNformats[typeN] or typeNformats[1]
if not _Format then
error(somethingMissing('typeN', typeN, typeNformats))
end
end
end
if typeN then _Format = mw.ustring.gsub(_Format, '%%3', typeN) end
if lineN then _Format = mw.ustring.gsub(_Format, '%%2', lineN) end
return (mw.ustring.match(_Format, '%[%[.+%]%]')) and (mw.ustring.gsub(_Format, '%%1', station)) or table.concat({'[[', mw.ustring.gsub(_Format, '%%1', station), '|', station, ']]'})
end
 
local function getTerminusText(var, Format)
local function subst(var1, var2)
-- var1 is the terminus or table of termini; var2 is the key for the table of termini
return type(var1) == 'string' and getStation(var1, (Format[var1] or Format[1]))
or type(var1) == 'table' and #var1 > 0 and getStation(var1[var2], (Format[var1[var2]] or Format[1]))
or ''
end
 
if Format then
if type(var) == 'string' then
return subst(var)
elseif type(var) == 'table' and #var > 0 then
local t = {subst(var, 1)}
 
for i = 2, #var - 1 do
t[i] = i18n[lang]['comma'](subst(var, i))
end
 
if #var > 1 then t[#var] = i18n[lang]['or'](subst(var, #var)) end
if var['via'] then
if i18n[lang]['via-first'] then
table.insert(t, 1, i18n[lang]['via'](subst(var, 'via')))
else
table.insert(t, i18n[lang]['via'](subst(var, 'via')))
end
end
 
return table.concat(t)
else
return ''
end
else
return var or ''
end
end
 
function p._main(_args) -- Arguments are processed here instead of the main function
local insert = table.insert
local lower = mw.ustring.lower
 
local yesno = require('Module:Yesno')
local trimq = require('Module:Trim quotes')._trim
 
local boolean = {
['oneway-left'] = true,
Line 205 ⟶ 149:
_args[k] = v:match('^%s*(.-)%s*$')
if _args[k] and _args[k] ~= '' then
local a = mw.ustring.match(k, '^(.*%D)%d+$') or k -- The parameter; address 1 can be omitted
local b = tonumber(mw.ustring.match(k, '^.*%D(%d+)$')) or 1 -- The address for a given argument; address 1 can be omitted
 
if boolean[a] then
Line 214 ⟶ 158:
if not args[b] then
args[b] = {[a] = v}
table.insert(index, b)
elseif args[b][a] then
return error(i18n[lang]['error_duplicate'](a .. b))
Line 233 ⟶ 177:
['header midcell'] = 'colspan="3" class="hmA"|',
['body cell'] = 'class="bcA"|',
['body banner'] = 'class="bbA notheme" style="color:inherit;background-color:#',
}
 
local Format
local function subst(var1, var2)
-- var1 is the terminus or table of termini; var2 is the key for the table of termini
return type(var1) == 'string' and getStation(var1, (Format[var1] or Format[1]))
or type(var1) == 'table' and #var1 > 0 and getStation(var1[var2], (Format[var1[var2]] or Format[1]))
or ''
end
 
local function station(var)
if Format then
if type(var) == 'string' then
return subst(var)
elseif type(var) == 'table' and #var > 0 then
local t = {subst(var, 1)}
 
for i = 2, #var - 1 do
t[i] = i18n[lang]['comma'](subst(var, i))
end
 
if #var > 1 then t[#var] = i18n[lang]['or'](subst(var, #var)) end
if var['via'] then
if i18n[lang]['via-first'] then
table.insert(t, 1, i18n[lang]['via'](subst(var, 'via')))
else
table.insert(t, i18n[lang]['via'](subst(var, 'via')))
end
end
 
return concat(t)
else
return ''
end
else
return var or ''
end
end
 
local function rgb(var)
Line 283 ⟶ 190:
 
local data = {} -- A table of data modules for each address
local wikitablenoclearclass = {(((_args.noclear or '{|') class~="wikitable '') and ' adjacent-stations"-noclear' or ''})
local wikitable = {'{| class="wikitable adjacent-stations' .. noclearclass .. '"'}
 
for i, v in ipairs(index) do
Line 290 ⟶ 198:
-- If an address has no system, the row uses data from the previous address
or data[index[i - 1]]
or (args[v]['header'] and getData(args[index[i+1]]['system']))
or error(i18n[lang]['error_unknown'](args[v]['system']))
 
local lang = data[v]['lang'] or lang
 
if args[v]['system'] and not args[v]['hide-system'] then -- Header row
local stop_noun = data[v]['header stop noun'] or i18n[lang]['stop_noun']
table.insert(wikitable, table.concat({'\n|-',
'\n! scope="col" ', style['header cell'], i18n[lang]['preceding'](stop_noun),
'\n! scope="col" ', style['header midcell'], (data[v]['system icon'] and data[v]['system icon'] .. ' ' or ''), (data[v]['system title'] or ('[['.. args[v]['system'] ..']]')),
'\n! scope="col" ', style['header cell'], i18n[lang]['following'](stop_noun)
}))
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
end
 
if args[v]['header'] then -- Subheader
table.insert(wikitable, '\n|-\n!colspan="5" class="hmA"|'.. args[v]['header'])
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
end
 
Line 321 ⟶ 230:
typeN = args[v]['type']
if data[v]['aliases'] then
lineN = data[v]['aliases'][mw.ustring.lower(lineN)] or lineN
if typeN then typeN = data[v]['aliases'][mw.ustring.lower(typeN)] or typeN end
end
 
Line 328 ⟶ 237:
local line = data[v]['lines'] and (mw.clone(data[v]['lines'][lineN]) or error(i18n[lang]['error_unknown'](args[v]['line']))) or error(i18n[lang]['error_line'])
local default = data[v]['lines']['_default'] or {}
line['title'] = line['title'] or default['title'] or ''
line['title'] = mw.ustring.gsub(line['title'], '%%1', lineN)
 
-- cell across row for non-stop service
if args[v]['nonstop'] then
table.insert(wikitable,
table.concat({'\n|-\n|colspan="5" ',
style['body cell'],
((args[v]['nonstop'] == 'former') and i18n[lang]['nonstop_past'] or i18n[lang]['nonstop_present'])(p._box({data = data[v], line = lineN, Type = typeN, inline = 'yes'}))
})
)
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
else
local Format = data[v]['station format'] or i18n[lang]['error_format']
 
local color, color_2, background_color, circular
local Type = line['types'] and line['types'][typeN] -- get the line type table
 
Line 353 ⟶ 262:
background_color = Type['background color'] or line['color']
color = Type['color']
elseif color_2 = Type['background colorcolor2'] thenor color
background_color = Type['background color']
color = line['color'] or default['color'] or ''
else
background_color = Type['background color'] or line['background color']
color = line['color'] or default['color'] or ''
color_2 = line['color2'] or color
end
if Type['circular'] then
-- Type may override the circular status of the line
circular = Type['circular']
end
else
background_color = line['background color']
color = line['color'] or default['color'] or ''
color_2 = line['color2'] or color
circular = line['circular']
end
 
Line 372 ⟶ 286:
local _through_data = getLine(data[v], _through)
if _through_data then _through = _through_data['title'] or _through end
sideCell[i] = _through and "''" .. i18n[lang]['through'](trimq(_through)) .. "''"
or "''" .. trimq((args[v]['reverse-' .. b]
or args[v]['reverse']) and i18n[lang]['reverse']
or i18n[lang]['terminus']) .. "''"
Line 384 ⟶ 298:
if args[v]['to-' .. b] then
terminusT = args[v]['to-' .. b]
local _or = mw.ustring.match(terminusT, i18n[lang]['or-format'])
if _or then
terminusT = mw.ustring.gsub(terminusT, i18n[lang]['or-format'], '\127_OR_\127')
terminusT = mw.ustring.gsub(terminusT, i18n[lang]['comma-format'], '\127_OR_\127')
end
local _via = (mw.ustring.match(terminusT, i18n[lang]['via-format']))
if _via then
terminusT = mw.ustring.gsub(terminusT, i18n[lang]['via-format'], '')
terminusT = mw.text.split(terminusT, '\127_OR_\127')
terminusT['via'] = _via
Line 404 ⟶ 318:
end
 
local mainText = args[v]['note-' .. b] and stationgetTerminusText(args[v][b], Format) .. small(args[v]['note-' .. b]) or stationgetTerminusText(args[v][b], Format)
 
local subText = (args[v]['oneway-' .. b] or line['oneway-' .. b]) and i18n[lang]['oneway']
or args[v][b] == terminusT and i18n[lang]['terminus']
or line['circular'] and terminusT
or i18n[lang]['towards'](stationgetTerminusText(terminusT, Format))
subText = small(subText, true)
 
Line 416 ⟶ 330:
end
 
table.insert(wikitable, '\n|-')
table.insert(wikitable, '\n|' .. style['body cell'] .. sideCell[1])
table.insert(wikitable, table.concat({'\n|', style['body banner'], color, '"|',
'\n|', (background_color and 'class="bcA" style="background-color:rgba(' .. table.concat(rgb(background_color), ',') .. ',.2)"|' or style['body cell']), line['title'],
 
-- Type; table key 'types' in subpages (datatype table, with strings as keys). If table does not exist then the input is displayed as the text
Line 428 ⟶ 342:
 
-- Transfer; uses system's station link table
(args[v]['transfer'] and small('transfer at ' .. stationgetTerminusText(args[v]['transfer'], Format), true) or ''),
 
'\n|', style['body banner'], colorcolor_2, '"|'}))
table.insert(wikitable, '\n|' .. style['body cell'] .. sideCell[2])
end
end
 
if args[v]['note-row'] then -- Note
insert(wikitable,if args[v]['\n|note-\n|colspan="5" row' .. style[]:match('body cell^%s*<tr']) ..or args[v]['note-row']:match('^%s*%|%-') then
table.insert(wikitable, '\n' .. args[v]['note-row'])
else
insert(wikitable, '')
table.insert(wikitable, '\n|-\n|colspan="5" ' .. style['body cell'] .. args[v]['note-row'])
end
table.insert(wikitable, '')
table.insert(wikitable, '')
table.insert(wikitable, '')
end
end
Line 451 ⟶ 369:
rowspan = rowspan + 1
end
t[n] = mw.ustring.gsub(t[n], '\n|class="', '\n|rowspan="' .. rowspan .. '" class="')
end
end
Line 460 ⟶ 378:
for i = 5, M, 4 do combine(wikitable, i) end
 
table.insert(wikitable, '\n|}')
 
return table.concat(wikitable)
end
 
Line 472 ⟶ 390:
return function (frame)
local args = getArgs(frame, {parentOnly = true})
return p[funcName](args, frame)
end
end
 
local function makeTemplateFunction(funcName)
-- makes a function that can be returned from #invoke, using
-- [[Module:Arguments]]
return function (frame)
local args = getArgs(frame, {frameOnly = true})
return p[funcName](args, frame)
end
Line 504 ⟶ 431:
line, lineN = getLine(data, lineN)
if typeN then
typeN = data['aliases'] and data['aliases'][mw.ustring.lower(typeN)] or typeN
Type = line['types'] and line['types'][typeN] and line['types'][typeN]['title'] or typeN
end
Line 511 ⟶ 438:
line_data = line or error(i18n[lang]['error_unknown'](lineN))
line = line_data['title'] or default['title'] or error(i18n[lang]['error_missing']('title'))
line = mw.ustring.gsub(line, '%%1', lineN)
end
else
Line 535 ⟶ 462:
 
if not inline then -- [[Template:Legend]]
result = '<div class="legend" style="-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid-column"><span class="legend-color" style="display:inline-block;min-width:1.5em25em;height:1.5em25em;line-height:1.25;margin:1px 0;border:1px solid black;color:inherit;background-color:#' .. color .. '"> </span> ' .. line .. result .. '</div>'
elseif inline == 'yes' then
result = '<span style="color:inherit;background-color:#' .. color .. ';border:1px solid #000">    </span> &nbsp;' .. line .. result
elseif inline == 'box' then
result = '<span style="color:inherit;background-color:#' .. color .. ';border:1px solid #000">    </span>' .. result
elseif inline == 'link' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:inherit;background-color:#' .. color .. ';border:1px solid #000">    </span>]]' .. result
else
result = '<span style="color:inherit;background-color:#' .. color .. ';border:1px solid #000">    </span>' .. result
end
elseif inline == 'square' then
result = '<span style="color:#' .. color .. ';line-height:initial">■</span> &nbsp;' .. line .. result
elseif inline == 'lsquare' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:#' .. color .. ';line-height:initial">■</span>]]'
Line 559 ⟶ 486:
result = '<span style="color:#' .. color .. ';line-height:initial">●</span> ' .. line .. result
elseif inline == 'ldot' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:#' .. color .. ';line-height:initial">●</span>]]'
Line 566 ⟶ 493:
end
elseif inline == 'small' then
result = '<span style="color:inherit;background-color:#' .. color .. '"> </span>' .. ' ' .. line .. result
else
local yesno = require("Module:Yesno")
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
local border_color, text_color
local color_box = data['color box format'] or data['rail box format'] or {}
if line_data then
if line_data['types'] and line_data['types'][typeN] then
Line 576 ⟶ 504:
border_color = Type_data['border color'] or line_data['border color'] or color
text_color = Type_data['text color'] or line_data['text color']
if color_box == 'title' and not args[4] then
lineN = Type_data['short name'] or line_data['short name'] or lineN
lineN = Type_data['short name'] or line_data['short name'] or require('Module:Delink')._delink{line}
else
lineN = Type_data['short name'] or line_data['short name'] or lineN
end
else
border_color = line_data['border color'] or color
text_color = line_data['text color']
if color_box == 'title' and not args[4] then
lineN = line_data['short name'] or lineN
lineN = line_data['short name'] or require('Module:Delink')._delink{line}
else
lineN = line_data['short name'] or lineN
end
end
else
border_color = color
end
local greatercontrasttext_color = text_color and '#' .. text_color or require('Module:Color contrast')._greatercontrast{color}
local bold = ';font-weight:bold'
text_color = text_color and '#' .. text_color or greatercontrast{color}
local bold =if (yesno(args.bold) == false) orthen ';font-weight:bold = '' end
if inline == 'route' then -- [[Template:RouteBox]]
if link then
result = '<span style="color:inherit;background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';padding:0 .3em">[[' .. link .. '|<span style="color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>]]</span>'
else
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';padding:0 .3em;color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
Line 596 ⟶ 532:
elseif inline == 'croute' then -- [[Template:Bahnlinie]]
if link then
result = '<span style="color:inherit;background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em">[[' .. link .. '|<span style="color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>]]</span>'
else
result = '<span style="color:inherit;background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em;color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
end
elseif inline == 'xroute' then -- [[Template:Bahnlinie]]
Line 605 ⟶ 541:
else
result = '<span style="border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em;color:#' .. color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
end
elseif inline == 'broute' then
if link then
result = '<span style="color:inherit;background-color:#' .. color .. ';border:.075em solid #000;padding:0 .3em">[[' .. link .. '|<span style="color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>]]</span>'
else
result = '<span style="background-color:#' .. color .. ';border:.075em solid #000;padding:0 .3em;color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. lineN .. '</span>'
end
else -- [[Template:Legend]] (fallback; duplication to simplify logic)
result = '<div class="legend" style="-webkit-column-break-inside:avoid;page-break-inside:avoid;break-inside:avoid-column"><span class="legend-color" style="display:inline-block;min-width:1.5em25em;height:1.5em25em;line-height:1.25;margin:1px 0;border:1px solid black;color:inherit;background-color:#' .. color .. '"> </span> ' .. line .. result .. '</div>'
end
end
 
result = mw.ustring.gsub(result, ':%s*#transparent', ':transparent')
 
return result
Line 621 ⟶ 563:
function p._icon(args, frame)
local system = args[1] or args.system
local line = args[2] or args.line
local Type = args[3] or args.type
local data = args.data
if system or data then
data = data or getData(system)
 
if not system and not data then
local icon, Format
return
end
 
line data = (getLine(data, line)or getData(system)
 
local line, line_name = getLine(data, args[2] or args.line)
if line then
 
if Type then
local icon
Type = data['aliases'] and data['aliases'][lower(Type)] or Type
local icon_format
Type = line['types'] and line['types'][Type] -- If there's no type table or entry for this type, then it can't have its own icon
 
Format = Type['icon format'] or data['type icon format']
if line then
icon = Type['icon']
local line_type = args[3] or args.type
end
if not (Format or icon)line_type then
line_type = data.aliases and data.aliases[mw.ustring.lower(line_type)] or line_type
Format = line['icon format'] or data['line icon format']
line_type = line.types and line.types[line_type] -- If there's no type table or entry for this type, then it can't have its own icon
icon = line['icon']
icon_format = line_type['icon format'] or data['type icon format']
 
if line_type.icon then
icon = line_type.icon
end
end
 
if not (Format or icon) then
Formatif = data['systemnot icon format']then
icon = data['system line.icon']
end
 
-- Only if there is no icon use the icon_format.
if Format then
if not icon and not icon_format then
if Format ~= 'image' then return p._box({data = data, [2] = (args[2] or args.line), [3] = Format, type = (args[3] or args.type), bold = args.bold, link = args.link}, frame) end
icon_format = line['icon format'] or data['line icon format']
end
 
local sizedefault = argsdata.sizelines._default or {}
if icon and string.find(icon, "%%1") and default and default.icon then
if size then
icon = mw.ustring.gsub(default.icon, '%%1', line_name)
if match(size, '%d$') then
size = '|' .. size .. 'px'
else
size = '|' .. size
end
-- Upright values are to be disabled until there is use of upright scaling in subpages; doesn't seem to work anyway as of 2018-08-10
local tmp = {
'|%s*%d*x?%d+px%s*([%]|])', -- '|%s*upright=%d+%.?%d*%s*([%]|])', '|%s*upright%s*([%]|])'
}
if match(icon, tmp[1]) then
icon = gsub(icon, tmp[1], size .. '%1')
-- elseif match(icon, tmp[2]) then
-- icon = gsub(icon, tmp[2], size .. '%1')
-- elseif match(icon, tmp[3]) then
-- icon = gsub(icon, tmp[3], size .. '%1')
else
icon = gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1' .. size .. '%2')
end
end
 
end
local link = args.link
 
if link then
if not icon then
if match(icon, '|%s*link=[^%]|]*[%]|]') then
icon = data['system icon']
icon = gsub(icon, '|%s*link=[^%]|]*([%]|])', '|link=' .. link .. '%1')
end
else
 
icon = gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|link=' .. link .. '%2')
if not icon_format then
icon_format = data['system icon format']
end
 
if icon_format then
if icon_format ~= 'image' then
icon = p._box({data = data, [2] = (args[2] or args.line), [3] = icon_format, type = (args[3] or args.type), bold = args.bold, link = args.link}, frame)
 
if args.name then
if line and line.title then
return icon .. " " .. line.title
end
return icon .. " " .. data["system title"]
end
end
end
 
local altsize = args.alt or linksize
if altsize then
if mw.ustring.match(iconsize, '|%s*alt=[^%]|]*[%]|]d$') then
iconsize = gsub(icon, '|%s*alt=[^%]|]*([%]|])', '|alt=' .. altsize .. '%1px')
else
size = '|' .. size
icon = gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|alt=' .. alt .. '%2')
end
end
-- Upright values are to be disabled until there is use of upright scaling in subpages; doesn't seem to work anyway as of 2018-08-10
local regex = {
'|%s*%d*x?%d+px%s*([%]|])', -- '|%s*upright=%d+%.?%d*%s*([%]|])', '|%s*upright%s*([%]|])'
}
if mw.ustring.match(icon, regex[1]) then
icon = mw.ustring.gsub(icon, regex[1], size .. '%1')
-- elseif mw.ustring.match(icon, regex[2]) then
-- icon = gsub(icon, regex[2], size .. '%1')
-- elseif mw.ustring.match(icon, regex[3]) then
-- icon = gsub(icon, regex[3], size .. '%1')
else
icon = mw.ustring.gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1' .. size .. '%2')
end
end
 
local link = args.link
return icon
if link then
if mw.ustring.match(icon, '|%s*link=[^%]|]*[%]|]') then
icon = mw.ustring.gsub(icon, '|%s*link=[^%]|]*([%]|])', '|link=' .. link .. '%1')
else
icon = mw.ustring.gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|link=' .. link .. '%2')
end
end
 
local alt = args.alt or link
if alt then
if mw.ustring.match(icon, '|%s*alt=[^%]|]*[%]|]') then
icon = mw.ustring.gsub(icon, '|%s*alt=[^%]|]*([%]|])', '|alt=' .. alt .. '%1')
else
icon = mw.ustring.gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|alt=' .. alt .. '%2')
end
end
 
if args.name then
if line and line.title then
return icon .. " " .. line.title
end
return icon .. " " .. data["system title"]
end
return icon
end
 
p.icon = makeInvokeFunction('_icon')
p['rail icon'] = makeTemplateFunction('_icon')
 
function p._line(args, frame)
Line 709 ⟶ 688:
line = (getLine(data, line)) or error(i18n[lang]['error_unknown'](line))
if Type then
Type = data['aliases'] and data['aliases'][mw.ustring.lower(Type)] or Type
Type = line['types'] and line['types'][Type] and line['types'][Type]['title'] or Type
end
Line 718 ⟶ 697:
end
 
if Type and Type ~= '' then
if line == '' then
line = Type
Line 730 ⟶ 709:
 
p.line = makeInvokeFunction('_line')
 
function p._shortline(args, frame)
local system = args[1] or args.system
lineN = args[2] or args.line
if not (system or lineN) then return '' end
local line, Type, line_data
typeN = args.type
local data = args.data
if system or data then
data = data or getData(system, true)
if data then
local default = data['lines']['_default'] or {}
line, lineN = getLine(data, lineN)
if typeN then
typeN = data['aliases'] and data['aliases'][mw.ustring.lower(typeN)] or typeN
Type = line['types'] and line['types'][typeN] and line['types'][typeN]['title'] or typeN
end
line_data = line or error(i18n[lang]['error_unknown'](lineN))
line = line_data['title'] or default['title'] or error(i18n[lang]['error_missing']('title'))
line = mw.ustring.gsub(line, '%%1', lineN)
else
line = frame:expandTemplate{ title = system .. ' lines', args = {lineN, ['branch'] = typeN} }
if mw.text.trim(line) == '' then return error(i18n[lang]['error_unknown'](lineN)) end
Type = typeN
end
 
local result
 
if Type and Type ~= '' then
if line == '' then
line = Type
else
result = ' – ' .. Type
end
end
if args.note then result = (result or '') .. ' ' .. args.note end
result = result or ''
 
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if line_data then
if line_data['types'] and line_data['types'][typeN] then
local Type_data = line_data['types'][typeN]
lineN = Type_data['short name'] or line_data['short name'] or lineN
else
lineN = line_data['short name'] or lineN
end
end
if link then
result = '[[' .. link .. '|' .. lineN .. ']]'
else
result = lineN
end
result = mw.ustring.gsub(result, ':%s*#transparent', ':transparent')
 
return result
end
end
 
p.shortline = makeInvokeFunction('_shortline')
 
function p._station(args, frame)
Line 745 ⟶ 785:
if data['aliases'] then
if lineN then
lineN = data['aliases'][mw.ustring.lower(lineN)] or lineN
end
if typeN then
typeN = data['aliases'][mw.ustring.lower(typeN)] or typeN
end
end
Line 764 ⟶ 804:
 
p.station = makeInvokeFunction('_station')
p['station link'] = makeTemplateFunction('_station')
 
function p._terminusTable(args, frame)
local system = args[1] or args.system
lineN = args[2] or args.line
local side = mw.ustring.sub(mw.ustring.lower(args[3] or args.side or ''), 1, 1)
typeN = args.type
local prefix = (side == 'r') and 'right' or 'left'
local data = args.data
 
if system or data then
data = data or getData(system, true)
end
if data then
local line = getLine(data, lineN) or error(i18n[lang]['error_unknown'](lineN))
if typeN and data and data['aliases'] then typeN = data['aliases'][mw.ustring.lower(typeN)] or typeN end
local Type = line['types'] and line['types'][typeN]
 
local circular
if Type then
if Type['circular'] then
-- Type may override the circular status of the line
circular = Type['circular']
end
else
circular = line['circular']
end
 
return Type and Type[prefix .. ' terminus'] or line[prefix .. ' terminus'], data['station format'] or i18n[lang]['error_format'], circular
else
local terminus = frame:expandTemplate{ title = 'S-line/' .. system .. ' ' .. prefix .. '/' .. lineN }
return mw.ustring.gsub(terminus, '{{{type}}}', typeN)
end
end
 
function p._terminus(args, frame)
local var, Format, circular = p._terminusTable(args, frame)
 
return circular and var or getTerminusText(var, Format)
end
 
p.terminus = makeInvokeFunction('_terminus')
 
function p._style(args, frame)
Line 863 ⟶ 945:
local code = mw.text.split(mw.ustring.gsub(args[1], '^%s*{{(.*)}}%s*$', '%1'), '%s*}}%s*{{%s*')
local system
local group = tonumber(args.offset or 0) or 0
local firstgroup = group + 1
local delete = {
['s-rail'] = true,
Line 898 ⟶ 981:
local remove_rows = {}
local data = {}
local noclear = false
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 (mw.ustring.match(code[i] or '', 'noclear%s*=%s*[a-z]')) then
noclear = true
end
if template == 's-line' then
data[i] = {}
Line 916 ⟶ 1,003:
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], "}", ""))
Line 984 ⟶ 1,071:
end
code = table.concat(code, '\n')
local t = {'{{Adjacent stations' .. (noclear and '|noclear=y\n' or ''), '\n}}'}
system = mw.ustring.match(code, '|system(%d*)=')
code = mw.ustring.gsub(code, '\n\n+', '\n')
if tonumber(system) > 1firstgroup 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|system1system'..firstgroup..'='..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