Mô đun:Trạm liền kề/sandbox

require('strict')

local p = {}

local lang = 'vi' -- 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:Trạm liền kề/i18n")
local function getData(system, verify)
if verify then
local title = mw.title.new('Mô đun:Trạm liền kề/' .. system -- .. '/sandbox'
)
if not (title and title.exists) then return nil end
end
return require('Mô đun:Trạm liền kề/' .. 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
end
end

local function getColor(data, system, line, Type, frame)
if system then
if line then return frame:expandTemplate{ title = system .. ' màu', args = {line, ['branch'] = Type} } end
return frame:expandTemplate{ title = system .. ' màu' }
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 lineN, typeN

local function getStation(station, _Format)
if type(_Format) == 'table' then
_Format = _Format[lineN] or _Format[1]
if type(_Format) == 'table' then
_Format = _Format[typeN] or _Format[1]
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({, station, })
end

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

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 = 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] = {[a] = v}
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 = { -- 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 table.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 = {)

return table.concat(wikitable)
end

local getArgs = require('Mô đun: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
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{ title = system .. ' lines', args = {lineN, ['branch'] = typeN} }
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 -- Template:Legend
result = ' ' .. line .. result ..
elseif inline == 'yes' then
result = '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' .. line .. result
elseif inline == 'box' then
result = '&nbsp;&nbsp;&nbsp;&nbsp;' .. result
elseif inline == 'link' then
local link = args.link or mw.ustring.match(line, '%[%[([^%[:|%]]+)[|%]]')
if link then
result = '&nbsp;&nbsp;&nbsp;&nbsp;' .. result
else
result = '&nbsp;&nbsp;&nbsp;&nbsp;' .. result
end
elseif inline == 'square' then
result = '■&nbsp;' .. 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 = '●&nbsp;' .. 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 = '&nbsp;' .. '&nbsp;' .. 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{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 require('Module:Delink')._delink{line}
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{color}
local bold = ';font-weight:bold'
if (yesno(args.bold) == false) then bold = end
if inline == 'route' then -- Template:RouteBox
if link then
result = .. lineN ..
else
result = .. lineN ..
end
elseif inline == 'croute' then -- Template:Bahnlinie
if link then
result = .. lineN ..
else
result = .. lineN ..
end
elseif inline == 'xroute' then -- Template:Bahnlinie
if link then
result = .. lineN ..
else
result = .. lineN ..
end
elseif inline == 'broute' then
if link then
result = .. lineN ..
else
result = .. lineN ..
end
else -- Template:Legend (fallback; duplication to simplify logic)
result = ' ' .. line .. result ..
end
end

result = mw.ustring.gsub(result, ':%stransparent', ':transparent')

return result
end
end

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({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 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 = {
'|%s%dx?%d+px%s([%]|])', -- '|%supright=%d+%.?%d%s([%]|])', '|%supright%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
if link then
if mw.ustring.match(icon, '|%slink=[^%]|][%]|]') then
icon = mw.ustring.gsub(icon, '|%slink=[^%]|]([%]|])', '|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, '|%salt=[^%]|][%]|]') then
icon = mw.ustring.gsub(icon, '|%salt=[^%]|]([%]|])', '|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')

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{ title = system .. ' lines', args = {line, ['branch'] = Type} }
if mw.text.trim(line) then return error(i18n[lang]['error_unknown'](lineN)) 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
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{ title = system .. ' stations', args = {['station'] = station, ['line'] = lineN, ['branch'] = typeN} }
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
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'} 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