Module:Sandbox/QwartaL1/Adjacent stations explained

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 = require("Module:Sandbox/QwartaL1/Adjacent stations/i18n")local function getData(system, verify) if verify then local title = mw.title.new('Module:Sandbox/QwartaL1/Adjacent stations/' .. system -- .. '/sandbox' ) if not (title and title.exists) then return nil end end return require('Module:Sandbox/QwartaL1/Adjacent stations/' .. system -- .. '/sandbox' )end

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 local line = data['lines'][lineN] or for k, v in pairs(default) do 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 endend

local function getColor(data, system, line, Type, frame) if system then if line then return frame:expandTemplate end return frame:expandTemplate 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 ) endend

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 local lineNformats = _Format _Format = lineNformats[lineN] or lineNformats[1] if not _Format 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.concatend

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 =

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 endend

function p._main(_args) -- Arguments are processed here instead of the main function

local yesno = require('Module:Yesno') local trimq = require('Module:Trim quotes')._trim

local boolean =

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 = 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 v = yesno(v) end

if not args[b] then args[b] = table.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 '

' .. s .. '

' or '

' .. s .. '

' end

local style =

local function rgb(var) if var:len

3 then return elseif var:len

6 then return end return end

local data = -- A table of data modules for each address local noclearclass = (((_args.noclear or ) ~= ) and ' adjacent-stations-noclear' or ) local wikitable = ')

return table.concat(wikitable)end

local getArgs = require('Module:Arguments').getArgs

local function makeInvokeFunction(funcName) -- makes a function that can be returned from #invoke, using -- return function (frame) local args = getArgs(frame,) return p[funcName](args, frame) endend

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]) endend

p.color = makeInvokeFunction('_color')

function p._box(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 local inline = args[3] or args.inline typeN = 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, 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 color = getColor(data, nil, lineN, typeN) if inline ~= 'box' then 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 color = getColor(nil, system, lineN, typeN, frame) if inline ~= 'box' then line = frame:expandTemplate if mw.text.trim(line)

then return error(i18n[lang]['error_unknown'](lineN)) end end Type = typeN 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 -- result = '

' .. line .. result .. '

' elseif inline

'yes' then result = '

 ' .. line .. result elseif inline

'box' then result = '

' .. result elseif inline

'link' then local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]') if link then result = ' ' .. result else result = '

' .. result end elseif inline

'square' then result = '

 ' .. line .. result elseif inline

'lsquare' then local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]') if link then result = '' else result = '

' end elseif inline

'dot' then result = '

' .. line .. result elseif inline

'ldot' then local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]') if link then result = '' else result = '

' end elseif inline

'small' then result = '

' .. ' ' .. 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 local Type_data = line_data['types'][typeN] 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 require('Module:Delink')._delink 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 require('Module:Delink')._delink else lineN = line_data['short name'] or lineN end end else border_color = color end text_color = text_color and '#' .. text_color or require('Module:Color contrast')._greatercontrast local bold = ';font-weight:bold' if (yesno(args.bold)

false) then bold = end if inline

'route' then -- if link then result = '

' .. lineN .. ']]' else result = '' .. lineN .. '' end elseif inline

'croute' then -- if link then result = '

' .. lineN .. ']]' else result = '' .. lineN .. '' end elseif inline

'xroute' then -- if link then result = '

' .. lineN .. ']]' else result = '' .. lineN .. '' end elseif inline

'broute' then if link then result = '

' .. lineN .. ']]' else result = '' .. lineN .. '' end else -- (fallback; duplication to simplify logic) result = ' ' .. line .. result .. '

' end end

result = mw.ustring.gsub(result, ':%s*#transparent', ':transparent')

return result endend

p.box = makeInvokeFunction('_box')

function p._icon(args, frame) local system = args[1] or args.system local data = args.data

if not system and not data then return end

data = data or getData(system)

local line, line_name = getLine(data, args[2] or args.line)

local icon local icon_format

if line then local line_type = args[3] or args.type if line_type then line_type = data.aliases and data.aliases[mw.ustring.lower(line_type)] or line_type 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_format = line_type['icon format'] or data['type icon format']

if line_type.icon then icon = line_type.icon end end

if not icon then icon = line.icon end

-- Only if there is no icon use the icon_format. if not icon and not icon_format then icon_format = line['icon format'] or data['line icon format'] end

local default = data.lines._default or if icon and string.find(icon, "%%1") and default and default.icon then icon = mw.ustring.gsub(default.icon, '%%1', line_name) end

end

if not icon then icon = data['system icon'] end

if not icon_format then icon_format = data['system icon format'] end

if icon_format then if icon_format ~= 'image' then icon = p._box(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 size = args.size if size then if mw.ustring.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 regex = 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 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 iconend

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'][mw.ustring.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 if mw.text.trim(line)

then return error(i18n[lang]['error_unknown'](lineN)) end end

if Type and Type ~= then if line

then line = Type else line = line .. ' – ' .. Type end end return line endend

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 lineN = args[3] or args.line typeN = 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 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 station = getStation(station, _Format) else station = station or end else station = frame:expandTemplate end

return station endend

p.station = makeInvokeFunction('_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 return mw.ustring.gsub(terminus, '', typeN) endend

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) 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

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

'#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 if tmp ~= then table.insert(result, tmp) end elseif style

'subheader' then tmp = frame:expandTemplate if tmp ~= then table.insert(result, 'background-color:#' .. tmp) local color = frame:expandTemplate if color ~= then table.insert(result, 'color:#' .. color) else local ratio = require('Module:Color contrast')._ratio if ratio < 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 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 resultend

function p.style(frame) local args = getArgs(frame,) return p._style(args, frame)end

function p.convert(frame) local args = frame.args local code = mw.text.split(mw.ustring.gsub(args[1], '^%s*%s*$', '%1'), '%s*}}%s*