Module:Adjacent stations
Lua error in Module:Documentation at line 144: message: type error in message cfg.container (string expected, got nil).
require('Module:No globals')
local p = {}
local lang = 'en-GB' -- local default language
-- Below these comments: Internationalization table
-- How to translate this module (for languages without variants):
-- • Characters inside single and double quotation marks are called strings.
-- The strings in this i18n table are used as output.
-- • Strings within square brackets are keys.
-- • Strings are concatenated (joined) with two dots.
-- • Set the string after «local lang =» to your language's code.
-- Change the first key after "i18n" (usually "en-GB") to the same thing.
-- • For each string which is not inside a function, translate it directly.
-- • Strings with keys named "format" are Lua regular expressions.
-- «()» is a match; «.+» means all characters; «%s+» means all spaces.
-- • For each string which is concatenated to the variable «var»,
-- translate the phrase assuming that «var» will be a noun.
-- • Remove any unnecessary translations.
local 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
local title = mw.title.new('Module:Adjacent stations/' .. system -- .. '/sandbox'
)
if not (title and title.exists) then return nil end
end
return require('Module:Adjacent stations/' .. system -- .. '/sandbox'
)
end
local lower = mw.ustring.lower
local gsub = mw.ustring.gsub
local function getLine(data, _line)
if _line then
if data['aliases'] then
_line = data['aliases'][lower(_line)] or _line
end
local default = data['lines']['_default'] or {}
local line = data['lines'][_line] or {}
for k, v in pairs(default) do
if v then line[k] = line[k] or v end
end
line['title'] = line['title'] and gsub(line['title'], '%%1', _line)
return line, _line
end
end
local function getColor(data, system, line, Type, frame)
if system then
if line then return frame:expandTemplate{ title = system .. ' color', args = {line, ['branch'] = Type} } end
return frame:expandTemplate{ title = system .. ' color' }
else
line = (getLine(data, line))
local default = data['lines']['_default']
if line or default then
default = default or {}
if not line then line = mw.clone(default) end
local color = line['color'] or line['background color'] or default['color'] or default['background color'] or data['system color']
local Type_value = Type and line['types'] and (line['types'][Type] and line['types'][Type]['color'])
if Type_value then color = Type_value end
return color
end
return (default and (default['color'] or default['background color']) or data['system color'] or '')
end
end
local match = mw.ustring.match
local concat = table.concat
local _line, _Type
local function getStation(station, _Format)
if type(_Format) == 'table' then
_Format = _Format[_line] or _Format[1]
if type(_Format) == 'table' then
_Format = _Format[_Type] or _Format[1]
end
end
if _Type then _Format = gsub(_Format, '%%3', _Type) end
if _line then _Format = gsub(_Format, '%%2', _line) end
return (match(_Format, '%[%[.+%]%]')) and (gsub(_Format, '%%1', station)) or concat({'[[', gsub(_Format, '%%1', station), '|', station, ']]'})
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 boolean = {
['oneway-left'] = true,
['oneway-right'] = true,
['reverse'] = true,
['reverse-left'] = true,
['reverse-right'] = true
}
local args = {} -- Processed arguments
local index = {} -- A list of addresses corresponding to number suffixes in the arguments
for k, v in pairs(_args) do -- Maps each raw argument to processed arguments by string matching
_args[k] = v:match('^%s*(.-)%s*$')
if _args[k] and _args[k] ~= '' then
local a = match(k, '^(.*%D)%d+$') or k -- The parameter; address 1 can be omitted
local b = tonumber(match(k, '^.*%D(%d+)$')) or 1 -- The address for a given argument; address 1 can be omitted
if boolean[a] then
v = yesno(v)
end
if not args[b] then
args[b] = {[a] = v}
insert(index, b)
elseif args[b][a] then
return error(i18n[lang]['error_duplicate'](a .. b))
else
args[b][a] = v
end
end
end
table.sort(index)
local function small(s, italic)
return italic and '<div class="isA">' .. s .. '</div>'
or '<div class="smA">' .. s .. '</div>'
end
local style = { -- Style for each cell type
['header cell'] = 'class="hcA"|',
['header midcell'] = 'colspan="3" class="hmA"|',
['body cell'] = 'class="bcA"|',
['body banner'] = 'class="bbA" style="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)
if var:len() == 3 then
return {tonumber(var:sub(1, 1), 16) * 17, tonumber(var:sub(2, 2), 16) * 17, tonumber(var:sub(2, 2), 16) * 17}
elseif var:len() == 6 then
return {tonumber(var:sub(1, 2), 16), tonumber(var:sub(3, 4), 16), tonumber(var:sub(5, 6), 16)}
end
return {}
end
local data = {} -- A table of data modules for each address
local wikitable = {'{| class="wikitable adjacent-stations"'}
for i, v in ipairs(index) do
-- If an address has a system argument, indexes the data module
data[v] = args[v]['system'] and getData(args[v]['system'])
-- If an address has no system, the row uses data from the previous address
or data[index[i - 1]]
or error(i18n[lang]['error_unknown'](args[v]['system']))
local lang = data[v]['lang'] or lang
if args[v]['system'] then -- Header row
local stop_noun = data[v]['header stop noun'] or i18n[lang]['stop_noun']
insert(wikitable, concat({'\n|-',
'\n!', style['header cell'], i18n[lang]['preceding'](stop_noun),
'\n!', style['header midcell'], (data[v]['system icon'] and data[v]['system icon'] .. ' ' or ''), (data[v]['system title'] or ('[['.. args[v]['system'] ..']]')),
'\n!', style['header cell'], i18n[lang]['following'](stop_noun)
}))
insert(wikitable, '')
insert(wikitable, '')
insert(wikitable, '')
end
if args[v]['header'] then -- Subheader
insert(wikitable, '\n|-\n!colspan="5" class="hmA"|'.. args[v]['header'])
insert(wikitable, '')
insert(wikitable, '')
insert(wikitable, '')
end
if args[v]['line'] or args[v]['left'] or args[v]['right'] or args[v]['nonstop'] then
if not args[v]['line'] and i > 1 and not args[v]['system'] then
args[v]['line'] = args[index[i - 1]]['line']
end
_line = args[v]['line'] or '_default'
_Type = args[v]['type']
if data[v]['aliases'] then
_line = data[v]['aliases'][lower(_line)] or _line
if _Type then _Type = data[v]['aliases'][lower(_Type)] or _Type end
end
-- get the line table
local line = data[v]['lines'] and (mw.clone(data[v]['lines'][_line]) 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']
line['title'] = gsub(line['title'], '%%1', _line)
-- cell across row for non-stop service
if args[v]['nonstop'] then
insert(wikitable,
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 = _line, Type = _Type, inline = 'yes'}))
})
)
insert(wikitable, '')
insert(wikitable, '')
insert(wikitable, '')
else
Format = data[v]['station format'] or i18n[lang]['error_format']
local color, background_color
local Type = line['types'] and line['types'][_Type] -- get the line type table
if Type then
if Type['color'] then
-- line color is used as background if there is no background color in the line type table
background_color = Type['background color'] or line['color']
color = Type['color']
elseif Type['background color'] then
background_color = Type['background color']
color = line['color'] or default['color'] or ''
else
background_color = line['background color']
color = line['color'] or default['color'] or ''
end
else
background_color = line['background color']
color = line['color'] or default['color'] or ''
end
-- Alternate termini can be specified based on type
local sideCell = {true, true}
for i, b in ipairs({'left', 'right'}) do
if not args[v][b] then -- If no station is given on one side, the station is assumed to be the terminus on that side
local _through = args[v]['through-' .. b] or args[v]['through']
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'](_through) .. "''"
or "''" .. ((args[v]['reverse-' .. b]
or args[v]['reverse']) and i18n[lang]['reverse']
or i18n[lang]['terminus']) .. "''"
else
local terminus
local _terminus = Type and Type[b .. ' terminus'] or line[b .. ' terminus']
-- If the terminus table has more than one numbered key or has the via key then the table shows only the default termini, since _terminus[2] cannot be used and _terminus[via] is reserved
if type(_terminus) == 'string' or (type(_terminus) == 'table' and (_terminus[2] or _terminus['via'])) then
if args[v]['to-' .. b] then
terminus = args[v]['to-' .. b]
local _or = match(terminus, i18n[lang]['or-format'])
if _or then
terminus = gsub(terminus, i18n[lang]['or-format'], '\127_OR_\127')
terminus = gsub(terminus, i18n[lang]['comma-format'], '\127_OR_\127')
end
local _via = (match(terminus, i18n[lang]['via-format']))
if _via then
terminus = gsub(terminus, i18n[lang]['via-format'], '')
terminus = mw.text.split(terminus, '\127_OR_\127')
terminus['via'] = _via
elseif _or then
terminus = mw.text.split(terminus, '\127_OR_\127')
end
else
terminus = _terminus
end
elseif type(_terminus) == 'table' then
terminus = _terminus[args[v]['to-' .. b]] or _terminus[args[v]['to']] or _terminus[1]
end
local mainText = args[v]['note-' .. b] and station(args[v][b]) .. small(args[v]['note-' .. b]) or station(args[v][b])
local subText = (args[v]['oneway-' .. b] or line['oneway-' .. b]) and i18n[lang]['oneway']
or args[v][b] == terminus and i18n[lang]['terminus']
or line['circular'] and terminus
or i18n[lang]['towards'](station(terminus))
subText = small(subText, true)
sideCell[i] = mainText .. subText
end
end
insert(wikitable, '\n|-')
insert(wikitable, '\n|' .. style['body cell'] .. sideCell[1])
insert(wikitable, concat({'\n|', style['body banner'], color, '"|',
'\n|', (background_color and 'class="bcA" style="background-color:rgba(' .. 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
(_Type and '<div>' .. (Type and Type['title'] or _Type) .. '</div>' or ''),
-- Note-mid; table key 'note-mid' in subpages. Overridden by user input
((args[v]['note-mid'] and small(args[v]['note-mid'])) or (Type and Type['note-mid'] and small(Type['note-mid'])) or (line['note-mid'] and small(line['note-mid'])) or ''),
-- Transfer; uses system's station link table
(args[v]['transfer'] and small('transfer at ' .. station(args[v]['transfer']), true) or ''),
'\n|', style['body banner'], color, '"|'}))
insert(wikitable, '\n|' .. style['body cell'] .. sideCell[2])
end
end
if args[v]['note-row'] then -- Note
insert(wikitable, '\n|-\n|colspan="5" ' .. style['body cell'] .. args[v]['note-row'])
insert(wikitable, '')
insert(wikitable, '')
insert(wikitable, '')
end
end
local function combine(t, n)
if t[n + 4] ~= '' and t[n + 4] == t[n] then
t[n + 4] = '' -- The cell in the next row is deleted
local rowspan = 2
while t[n + rowspan * 4] == t[n] do
t[n + rowspan * 4] = ''
rowspan = rowspan + 1
end
t[n] = gsub(t[n], '\n|class="', '\n|rowspan="' .. rowspan .. '" class="')
end
end
local M = #wikitable
for i = 3, M, 4 do combine(wikitable, i) end
for i = 4, M, 4 do combine(wikitable, i) end
for i = 5, M, 4 do combine(wikitable, i) end
insert(wikitable, '\n|}')
return concat(wikitable)
end
local getArgs = require('Module:Arguments').getArgs
local function makeInvokeFunction(funcName)
-- makes a function that can be returned from #invoke, using
-- [[Module:Arguments]]
return function (frame)
local args = getArgs(frame, {parentOnly = true})
return p[funcName](args, frame)
end
end
p.main = makeInvokeFunction('_main')
function p._color(args, frame)
local data = args.data
if args[1] or data then
data = data or getData(args[1], true)
if not data then return getColor(nil, args[1], args[2], args[3], frame) end
return getColor(data, nil, args[2], args[3])
end
end
p.color = makeInvokeFunction('_color')
function p._box(args, frame)
local system = args[1] or args.system
local _line = args[2] or args.line
if not (system or _line) then return '' end
local line, Type, line_data
local inline = args[3] or args.inline
local _Type = args.type
local data = args.data
if system or data then
data = data or getData(system, true)
local color
if data then
local default = data['lines']['_default'] or {}
line, _line = getLine(data, _line)
if _Type then
_Type = data['aliases'] and data['aliases'][lower(_Type)] or _Type
Type = line['types'] and line['types'][_Type] and line['types'][_Type]['title'] or _Type
end
color = getColor(data, nil, _line, _Type)
if inline ~= 'box' then
line_data = line or error(i18n[lang]['error_unknown'](_line))
line = line_data['title'] or default['title'] or error(i18n[lang]['error_missing']('title'))
line = gsub(line, '%%1', _line)
end
else
color = getColor(nil, system, _line, _Type, frame)
if inline ~= 'box' then
line = frame:expandTemplate{ title = system .. ' lines', args = {_line, ['branch'] = _Type} }
if mw.text.trim(line) == '' then return error(i18n[lang]['error_unknown'](_line)) end
end
Type = _Type
end
local result
if Type and Type ~= '' and inline ~= 'box' then
if line == '' then
line = Type
else
result = ' – ' .. Type
end
end
if args.note then result = (result or '') .. ' ' .. args.note end
result = result or ''
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;width:1.5em;height:1.5em;margin:1px 0;border:1px solid black;background-color:#' .. color .. '"> </span> ' .. line .. result .. '</div>'
elseif inline == 'yes' then
result = '<span style="background-color:#' .. color .. ';border:1px solid #000"> </span> ' .. line .. result
elseif inline == 'box' then
result = '<span style="background-color:#' .. color .. ';border:1px solid #000"> </span>' .. result
elseif inline == 'link' then
local link = args.link or match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="background-color:#' .. color .. ';border:1px solid #000"> </span>]]' .. result
else
result = '<span style="background-color:#' .. color .. ';border:1px solid #000"> </span>' .. result
end
elseif inline == 'square' then
result = '<span style="color:#' .. color .. ';line-height:initial">■</span> ' .. line .. result
elseif inline == 'lsquare' then
local link = args.link or match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:#' .. color .. ';line-height:initial">■</span>]]'
else
result = '<span style="color:#' .. color .. ';line-height:initial">■</span>'
end
elseif inline == 'dot' then
result = '<span style="color:#' .. color .. ';line-height:initial">●</span> ' .. line .. result
elseif inline == 'ldot' then
local link = args.link or match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '[[' .. link .. '|<span style="color:#' .. color .. ';line-height:initial">●</span>]]'
else
result = '<span style="color:#' .. color .. ';line-height:initial">●</span>'
end
elseif inline == 'small' then
result = '<span style="background-color:#' .. color .. '"> </span>' .. ' ' .. line .. result
else
local yesno = require("Module:Yesno")
local link = args.link or match(line, '%[%[([^%[:|%]]+)[|%]]')
local border_color, text_color
if line_data then
if line_data['types'] and line_data['types'][_Type] then
local Type_data = line_data['types'][_Type]
border_color = Type_data['border color'] or line_data['border color'] or color
text_color = Type_data['text color'] or line_data['text color']
_line = Type_data['short name'] or line_data['short name'] or _line
else
border_color = line_data['border color'] or color
text_color = line_data['text color']
_line = line_data['short name'] or _line
end
else
border_color = color
end
local greatercontrast = require('Module:Color contrast')._greatercontrast
text_color = text_color and '#' .. text_color or greatercontrast{color}
local bold = (yesno(args.bold) == false) or ';font-weight:bold'
if inline == 'route' then -- [[Template:RouteBox]]
if link then
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';padding:0 .3em">[[' .. link .. '|<span style="color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. _line .. '</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">' .. _line .. '</span>'
end
elseif inline == 'croute' then -- [[Template:Bahnlinie]]
if link then
result = '<span style="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">' .. _line .. '</span>]]</span>'
else
result = '<span style="background-color:#' .. color .. ';border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em;color:' .. text_color .. bold .. ';font-size:inherit;white-space:nowrap">' .. _line .. '</span>'
end
elseif inline == 'xroute' then -- [[Template:Bahnlinie]]
if link then
result = '<span style="border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em">[[' .. link .. '|<span style="color:#' .. color .. bold .. ';font-size:inherit;white-space:nowrap">' .. _line .. '</span>]]</span>'
else
result = '<span style="border:.075em solid #' .. border_color .. ';border-radius:.5em;padding:0 .3em;color:#' .. color .. bold .. ';font-size:inherit;white-space:nowrap">' .. _line .. '</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;width:1.5em;height:1.5em;margin:1px 0;border:1px solid black;background-color:#' .. color .. '"> </span> ' .. line .. result .. '</div>'
end
end
result = gsub(result, ':%s*#transparent', ':transparent')
return result
end
end
p.box = makeInvokeFunction('_box')
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)
local icon, Format
line = (getLine(data, line))
if line then
if Type then
Type = data['aliases'] and data['aliases'][lower(Type)] or Type
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']
icon = Type['icon']
end
if not (Format or icon) then
Format = line['icon format'] or data['line icon format']
icon = line['icon']
end
end
if not (Format or icon) then
Format = data['system icon format']
icon = data['system icon']
end
if 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
end
local size = args.size
if size then
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
local link = args.link
if link then
if match(icon, '|%s*link=[^%]|]*[%]|]') then
icon = gsub(icon, '|%s*link=[^%]|]*([%]|])', '|link=' .. link .. '%1')
else
icon = gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|link=' .. link .. '%2')
end
end
local alt = args.alt or link
if alt then
if match(icon, '|%s*alt=[^%]|]*[%]|]') then
icon = gsub(icon, '|%s*alt=[^%]|]*([%]|])', '|alt=' .. alt .. '%1')
else
icon = gsub(icon, '(%[%[[^%]|]+)([%]|])', '%1|alt=' .. alt .. '%2')
end
end
return icon
end
end
p.icon = makeInvokeFunction('_icon')
function p._line(args, frame)
local system = args[1] or args.system
local line = args[2] or args.line
if not line then return '' end
local Type = args[3] or args.type
local data = args.data
if system or data then
data = data or getData(system, true)
if data then
line = (getLine(data, line)) or error(i18n[lang]['error_unknown'](line))
if Type then
Type = data['aliases'] and data['aliases'][lower(Type)] or Type
Type = line['types'] and line['types'][Type] and line['types'][Type]['title'] or Type
end
line = line['title'] or error(i18n[lang]['error_missing']('title'))
else
line = frame:expandTemplate{ title = system .. ' lines', args = {line, ['branch'] = Type} }
if mw.text.trim(line) == '' then return error(i18n[lang]['error_unknown'](_line)) end
end
if Type then
if line == '' then
line = Type
else
line = line .. ' – ' .. Type
end
end
return line
end
end
p.line = makeInvokeFunction('_line')
function p._station(args, frame)
local system = args[1] or args.system
local station = args[2] or args.station
if not station then return '' end
local _line = args[3] or args.line
local _Type = args[4] or args.type
local data = args.data
if system or data then
data = data or getData(system, true)
if data then
local _Format = data['station format'][station] or data['station format'][1]
if _Format then
if data['aliases'] then
if _line then
_line = data['aliases'][lower(_line)] or _line
end
if _Type then
_Type = data['aliases'][lower(_Type)] or _Type
end
end
station = getStation(station, _Format)
else
station = station or ''
end
else
station = frame:expandTemplate{ title = system .. ' stations', args = {['station'] = station, ['line'] = _line, ['branch'] = _Type} }
end
return station
end
end
p.station = makeInvokeFunction('_station')
function p._style(args, frame)
local style = args[1] or args.style
local system = args[2] or args.system
local line = args[3] or args.line
local station = args[4] or args.station
local result = {}
local data = args.data
local default = 'background-color:#efefef' -- Default background color for {{Infobox station}}
if system or data then
data = data or getData(system, true)
end
if data then
local function getValue(var)
if type(var) == 'table' then
var = var[line] or var[1]
if type(var) == 'table' then
var = var[station] or var[1]
end
end
if var ~= '' then return var end
end
if style == 'header' then
local tmp = data['name format'] and getValue(data['name format'])
if tmp then table.insert(result, tmp) end
elseif style == 'subheader' then
local tmp = data['header background color'] and getValue(data['header background color'])
if tmp then
table.insert(result, 'background-color:#' .. tmp)
local color = data['header text color'] and getValue(data['header text color'])
if color then
table.insert(result, 'color:#' .. color)
else
local greatercontrast = require('Module:Color contrast')._greatercontrast
if greatercontrast{tmp} == '#FFFFFF' then table.insert(result, 'color:#FFFFFF') end
end
else
table.insert(result, default)
local color = data['header text color'] and getValue(data['header text color'])
if color then table.insert(result, 'color:#' .. color) end
end
end
result = table.concat(result, ';')
elseif system then
local title = 'Template:' .. system .. ' style'
local titleObj = mw.title.new(title)
if titleObj and titleObj.exists then
local tmp
if style == 'header' then
tmp = frame:expandTemplate{ title = title, args = {'name_format', line, station} }
if tmp ~= '' then table.insert(result, tmp) end
elseif style == 'subheader' then
tmp = frame:expandTemplate{ title = title, args = {'thbgcolor', line, station} }
if tmp ~= '' then
table.insert(result, 'background-color:#' .. tmp)
local color = frame:expandTemplate{ title = title, args = {'thcolor', line, station} }
if color ~= '' then
table.insert(result, 'color:#' .. color)
else
local ratio = require('Module:Color contrast')._ratio
if ratio{tmp, '222222'} < 4.5 then table.insert(result, 'color:#FFFFFF') end -- 222222 is the default text color in Vector
end
else
table.insert(result, default)
tmp = frame:expandTemplate{ title = title, args = {'thcolor', line, station} }
if tmp ~= '' then
table.insert(result, 'color:#' .. tmp)
end
end
end
result = table.concat(result, ';')
else
if style == 'subheader' then
result = default
else
result = ''
end
end
else
if style == 'subheader' then
result = default
else
result = ''
end
end
return result
end
function p.style(frame)
local args = getArgs(frame, {frameOnly = true})
return p._style(args, frame)
end
return p