Module:Routemap
Appearance
For usage instruction, read the documentation in {{Routemap}} template page.
local i18n = {
errors = {
["parameter-missing"] = "Missing parameter!",
["collapsible-block-not-closed"] = "Collapsible section not closed properly!",
["collapsible-block-not-open"] = "Missing start-Collapsible markup!",
["collapsible-block-empty"] = "Collapsible section must not be empty!",
["collapsible-block-no-first-row"] = "Invalid first row of collapsible section!",
["collapsible-block-no-replacement"] = "Invalid collapsible replacement row!",
["colspan-less-rows-than-set"] = "Invalid colspan set!",
},
["error-categories"] = {
default = '[[Category:Pages with errors of Module Routemap]]'
},
html = {
["cell-icon-fmt"] = '\
|style="padding:0"|[[File:BSicon_%s.svg|x20px|link=%s|alt=]]',
["cell-overlapicon-fmt"] = '<div style="position:absolute;left:0px;top:0px;padding:0">[[File:BSicon_%s.svg|x20px|link=%s|alt=]]</div>',
["cell-icon-fmt-with-overlap"] = '\
|style="padding:0"|<div style="position:relative">%s</div>[[File:BSicon_%s.svg|x20px|link=|alt=]]',
["cell-filler-fmt"] = '\n|style="width:8px"| ||style="width:4px; background-color:%s"| ||style="width:8px"|',
["cell-filler-empty-fmt"] = '\n|style="width:%s;min-width:%s;padding:0"|',
["row-linfo4-fmt"] = '\
|style="vertical-align:middle;padding:0 3px 0 0;text-align:left;%s"|<span style="font-size:90%%;">%s</span>',-- parameters:linfo4-width, linfo4
["row-linfo3-fmt"] = '<span style="font-size:90%%;">%s</span> ',
["row-rinfo3-fmt"] = ' <span style="font-size:90%%;">%s</span>',
["row-rinfo4-fmt"] = '\
|style="vertical-align:middle;padding:0 0 0 3px;text-align:right;%s"|<span style="font-size:90%%;">%s</span>',-- parameters:rinfo4-width, rinfo4
["row-general-fmt"] = '\
|- style="line-height:1" %s\
|colspan="%s" style="vertical-align:middle;padding:0;text-align:right;%s"|%s\
|style="vertical-align:middle;text-align:left;padding:0 %s;%s"|<span style="font-size:90%%;">%s</span>\
|style="padding:0;background-color:%s"|<center>\
{|cellspacing="0" cellpadding="0" style="line-height: 0px !important;padding:0 !important; margin: 0 !important"\
|-%s\
|}</center>\
|style="vertical-align:middle;text-align:right;padding:0 %s;%s"|<span style="font-size:90%%;">%s</span>\
|colspan="%s" style="vertical-align:middle;padding:0;text-align:left;%s"|%s%s',-- parameters: linfo4-fmt, colspan-left, linfo3+2-width, linfo3+2, linfo1-pad, linfo1-width, linfo1, bg, cells, rinfo1-pad, rinfo1-width, rinfo1, colspan-right, rinfo2+3-width, rinfo2+3, rinfo4-fmt
["row-collapsible-begin-fmt"] = '\
|- style="line-height:1"\
|colspan="7" style="padding:0 !important;background-color:%s"|\
{|class="%s%s" cellpadding="0" cellspacing="0" style="%s padding:0 !important;vertical-align:middle;margin:0 !important;white-space:nowrap"',-- parameters: bg, "collapsible "/"mw-collapsible mw-", collapse-state, "float:right" / ""
["row-collapsible-end-fmt"] = '\n|}',
["row-collapsible-left-button-width"] = '45px',-- 50px is the minimal width for [показать] / [скрыть] button. Use 40px for [show] / [hide]
["row-collapsible-left-button-fmt"] = '\n! style="padding-right:3px;min-width:%s;%s" |',--parameters: left-button-width, linfo4-width
["row-collapsible-left-linfo4+3+2-fmt"] = '\
{|cellspacing="0" cellpadding="0" width="100%%" style="line-height:1;padding:0 !important;margin:0 !important"\
|style="vertical-align:middle;padding:0 3px 0 1px;text-align:left"| <span style="font-size:90%%;">%s</span>\
|style="vertical-align:middle;text-align:right"| %s\
|}',-- parameters: linfo4, linfo3+2
["row-collapsible-right-button-width"] = '45px',-- 72px is the minimal width for [развернуть] / [свернуть] button at 90%. Use 58px for [expand] / [collapse]
["row-collapsible-right-rinfo2+3+4-fmt"] = '\
{|cellspacing="0" cellpadding="0" width="100%%" style="line-height:1;padding:0 !important;margin:0 !important"\
|style="vertical-align:middle;text-align:left"| %s\
|style="vertical-align:middle;padding:0 1px 0 3px;text-align:right"| <span style="font-size:90%%;">%s</span>\
|}',-- parameters: rinfo2+3, linfo4
["row-collapsible-right-button-fmt"] = '\n| style="padding-left:3px;font-size:90%%;min-width:%s;%s" |',--parameters: right-button-width, rinfo4-width
["row-collapsible-replace-begin-fmt"] = '\
|- style="line-height:1"\
|colspan="7" style="padding:0 %s"|<div style="position:relative">\
{| cellspacing="0" cellpadding="0" style="position:absolute;bottom:0px;%s vertical-align:middle;white-space:nowrap;background-color:%s"',-- parameters: "right-button-width 0 0" / "0 0 left-button-width", "right:0px" / "", bg
["row-collapsible-replace-end-fmt"] = '\n|}</div>',
["colspan-fmt"] = '%s\n|-\n| colspan="7" style="background-color:%s;text-align:%s;%s"|\n%s',
["empty-row-fmt"] = '\n|-\n| style="padding-right:3px;%s" |\n| style="%s" |\n| style="padding:0 %s;%s" |\n|\n| style="padding:0 %s;%s" |\n| style="%s" |\n| style="padding-left:3px;%s" |'
}
}
local p,q={},{}
local function formaterror(key,param)
local result = mw.ustring.format(i18n.html['colspan-fmt'], '', '', '', '', '<span class="error">' .. mw.ustring.format(i18n.errors[key] or (tostring(key) .. ' %s'),
tostring(param or '')) .. '</span>')
if mw.site.namespaces[mw.title.getCurrentTitle().namespace].isContent then result = result .. (i18n['errors-categories'][key] or i18n['errors-categories'].default or '') end
return result
end
local function RGBbyCode(code)-- RGB codes for BSicon sets at Commons:Category:Icons for railway descriptions/other colors
local colors = {-- Any changes should be discussed at Commons:Talk:BSicon/Colors
bahn = 'BE2D2C', ex = 'D77F7E',
u = '003399', uex = '6281C0',
f = '008000', fex = '64B164',
g = '2CA05A', gex = '7EC49A',
azure = '3399FF', ex_azure = '99CCFF',
black = '000000', ex_black = '646464',
blue = '0078BE', ex_blue = '64ACD6',
brown = '8D5B2D', ex_brown = 'B89A7F',
cerulean = '1A8BB9', ex_cerulean = '73B7D3',
cyan = '40E0D0', ex_cyan = '8AEAE1',
denim = '00619F', ex_denim = '649EC3',
fuchsia = 'B5198D', ex_fuchsia = 'D173B8',
golden = 'D7C447', ex_golden = 'E5DA8E',
green = '2DBE2C', ex_green = '7FD67E',
grey = '999999', ex_grey = 'C0C0C0',
jade = '53B147', ex_jade = '95CE8E',
lavender = '9999FF', ex_lavender = 'C0C0FF',
lime = '99CC00', ex_lime = 'D1E681',
maroon = '800000', ex_maroon = 'B16464',
ochre = 'CC6600', ex_ochre = 'DEA164',
orange = 'FF6600', ex_orange = 'FF9955',
pink = 'F0668D', ex_pink = 'F4A1B8',
purple = '8171AC', ex_purple = 'B1A8CB',
red = 'EF161E', ex_red = 'F37176',
ruby = 'CC0066', ex_ruby = 'DE64A1',
saffron = 'FFAB2E', ex_saffron = 'FFC969',
sky = '069DD3', ex_sky = '67C2E3',
steel = 'A1B3D4', ex_steel = 'C4CFE3',
teal = '339999', ex_teal = '82C0C0',
violet = '800080', ex_violet = 'B164B1',
yellow = 'FFD702', ex_yellow = 'FFEB81',
}
return colors[code] or colors.bahn
end
local function cell(icon,overlapIcons)
--Icon handling. Each icon is defined as in the following example:
--icon ID!~overlap icon ID!@image link target
--No limit on overlap icons, just separate them by "!~".
local tmp,link={},''
if #overlapIcons>0 then
tmp = mw.text.split(overlapIcons[#overlapIcons], '!@')
overlapIcons[#overlapIcons] = tmp[1]
if #tmp > 1 then link = tmp[2] end
tmp = {}
for i,v in ipairs(overlapIcons) do
if i==#overlapIcons then local link=link else local link='' end
table.insert(tmp,mw.ustring.format(i18n.html['cell-overlapicon-fmt'],mw.text.trim(v),link))end
return mw.ustring.format(i18n.html['cell-icon-fmt-with-overlap'],mw.text.trim(table.concat(tmp)),icon)
end
tmp = mw.text.split(icon, '!@')
icon = mw.text.trim(tmp[1])
if #tmp > 1 then link = tmp[2] end
if icon ~= '' then
return mw.ustring.format(i18n.html['cell-icon-fmt'], icon, link)
else
return mw.ustring.format(i18n.html['cell-filler-empty-fmt'], '20px', '20px')
end
end
local function fillercell(code)
if code == '' then
return mw.ustring.format(i18n.html['cell-filler-empty-fmt'], '20px', '20px')
elseif code == 'd' then
return mw.ustring.format(i18n.html['cell-filler-empty-fmt'], '10px', '10px')
elseif string.sub(code,1,1) == '#' then
return mw.ustring.format(i18n.html['cell-filler-fmt'], code)
else
return mw.ustring.format(i18n.html['cell-filler-fmt'],'#' .. RGBbyCode(code))
end
end
local function properties(str)
--str is a combination of properties with following syntax:
--[property name=value[!@property name1=value1[!@property name1=value1]]] and so on
local result = {}
for i, v in ipairs(mw.text.split(str, '!@')) do
if v ~= '' then
local t = mw.text.split(v, '=')
table.insert(result, t[1])
result[t[1]] = table.concat(t, '=', 2) or ''--fill table with pairs "property"="value"
end
end
return result
end
local function row(pattern,noformatting,filler)
--Row handling. Each row looks like the following:
--row properties~~linfo4~~linfo3~~linfo2~~linfo1! !(icon pattern)~~rinfo1~~rinfo2~~rinfo3~~rinfo4~~row properties
local result = {['linfo4'] = '', ['linfo3+2'] = '', ['linfo1'] = '', ['cells'] = {}, ['rinfo1'] = '', ['rinfo2+3'] = '', ['rinfo4'] = '', ['rowProp'] = {}}
local lcolspan, rcolspan, linfo4_fmt, rinfo4_fmt = '2', '2', '', ''
local left, right, icons, overlapIcons, tmp = {}, {}, {}, {}, mw.text.split(pattern, '! !')
if #tmp > 1 then--splitting the pattern by '! !'
left = tmp[1] ; right = tmp[2]
else
left = '' ; right = tmp[1] or ''
end
tmp = mw.text.split(left, '~~')--analysing the left part
if #tmp > 1 then--if there are several ~~
result['linfo1'] = mw.getCurrentFrame():preprocess(mw.text.trim(tmp[#tmp]))
result['linfo3+2'] = mw.text.trim(tmp[#tmp - 1])
if #tmp > 2 then
tmp[#tmp - 2] = mw.text.trim(tmp[#tmp - 2])
if tmp[#tmp - 2] ~= '' then result['linfo3+2'] = mw.ustring.format(i18n.html['row-linfo3-fmt'], tmp[#tmp - 2]) .. result['linfo3+2'] end
if #tmp > 3 then
tmp[#tmp - 3] = mw.text.trim(tmp[#tmp - 3])
if tmp[#tmp - 3] ~= '' then
result['linfo4'] = mw.getCurrentFrame():preprocess(tmp[#tmp - 3])
lcolspan = '1'
linfo4_fmt = mw.ustring.format(i18n.html['row-linfo4-fmt'], '', result['linfo4'])
end
if #tmp > 4 then result['rowProp'] = properties(mw.text.trim(tmp[#tmp - 4])) end
end
end
else--assume only linfo2 was provided.
result['linfo3+2'] = mw.text.trim(tmp[1])
end
result['linfo3+2'] = mw.getCurrentFrame():preprocess(result['linfo3+2'])--expand possible templates in info.
tmp = mw.text.split(right, '~~')--analysing the right part
if #tmp > 2 then
result['rinfo1'] = mw.getCurrentFrame():preprocess(mw.text.trim(tmp[2]))
result['rinfo2+3'] = mw.text.trim(tmp[3])
if #tmp > 3 then
tmp[4] = mw.text.trim(tmp[4])
if tmp[4] ~= '' then result['rinfo2+3'] = result['rinfo2+3'] .. mw.ustring.format(i18n.html['row-rinfo3-fmt'], tmp[4]) end
if #tmp > 4 then
tmp[5] = mw.text.trim(tmp[5])
if tmp[5] ~= '' then
result['rinfo4'] = mw.getCurrentFrame():preprocess(tmp[5])
rcolspan = '1'
rinfo4_fmt = mw.ustring.format(i18n.html['row-rinfo4-fmt'], '', result['rinfo4'])
end
if #tmp > 5 then result['rowProp'] = properties(mw.text.trim(tmp[6])) end
end
end
else--assume only rinfo2 was provided.
result['rinfo2+3'] = mw.text.trim(tmp[2] or '')
end
result['rinfo2+3'] = mw.getCurrentFrame():preprocess(result['rinfo2+3'])
icons = mw.text.split(tmp[1], '\\')--splitting the string of icons first by "\"
if type(filler) == 'string' then
result['cells'][1] = 'style="height:' .. filler .. '"'--row parameter before any cells
for i, v in ipairs(icons) do table.insert(result['cells'], fillercell(v)) end--no !@ or !~ for filler row
else
for i, v in ipairs(icons) do
tmp = mw.text.split(v, '!~')
icons[i] = tmp[1]
table.remove(tmp, 1)
table.insert(overlapIcons, tmp)
end
for i, v in ipairs(icons) do table.insert(result['cells'], cell(v, overlapIcons[i])) end
end
result['cells'] = table.concat(result['cells'])
if result['rowProp']['bg'] == nil or result['rowProp']['bg'] == '' then result['rowProp']['bg'] = 'transparent' end
if noformatting then
return result
else
return mw.ustring.format(i18n.html['row-general-fmt'], linfo4_fmt, lcolspan, '', result['linfo3+2'], q.linfo1_pad, '', result['linfo1'], result['rowProp']['bg'],
result['cells'], q.rinfo1_pad, '', result['rinfo1'], rcolspan, '', result['rinfo2+3'], rinfo4_fmt)
end
end
q = {collapsibles = -1, text_width = {'', '', '', '', '', ''}, linfo1_pad = '3px', rinfo1_pad = '3px', bg = '#f9f9f9'}
q.isKeyword = function(pattern, i, rows, justTest)
if string.sub(pattern, 1, 1) ~= '-' then if justTest then return false else return nil end end--not a valid keyword
local tmp = mw.text.split(string.sub(pattern, 2), '%-')
if type(q[tmp[1]])=="function" and tmp[1] ~= 'isKeyword' then
if justTest then return tmp[1] else return q[tmp[1]](tmp, i, rows) end--valid keyword
else
if justTest then return false else return nil end
end
end
q['startCollapsible'] = function(params, i, rows)
table.remove(rows, i)
local tmp = q.isKeyword(rows[i], i, rows, true)
if tmp then
if tmp == 'endCollapsible' then return formaterror('collapsible-block-empty')
else return formaterror('collapsible-block-no-first-row') .. q.isKeyword(rows[i], i, rows) --no valid keywords that can follow "startCollapsible"
end
end
if q.collapsibles == -1 then q.collapsibles = 1 else q.collapsibles = q.collapsibles + 1 end--q.collapsibles == -1 means there are no collapsibles at all; 0 - all closed; >0 - some not closed
local collapsed, replace, props = params[2], params[3] or '', properties(table.concat(params, '-', 4))--params[1] is the keyword name so all indices are shifted by one.
if collapsed == nil or collapsed == '' then collapsed = 'collapsed' end
if props['bg'] == nil or props['bg'] == '' then props['bg'] = 'transparent' ; props['bg-replace'] = q.bg else props['bg-replace'] = props['bg'] end
local mode, float, result
if q.rinfo1_pad == '' then mode = 'collapsible ' ; float = 'float:right;'
else mode = 'mw-collapsible mw-' ; float = ''
end
result = mw.ustring.format(i18n.html["row-collapsible-begin-fmt"], props['bg'], mode, collapsed, float)
tmp = row(rows[i], true, nil)
local linfo4_3_2_fmt, rinfo2_3_4_fmt = '', ''
if q.rinfo1_pad == '' then
if tmp['linfo4'] ~= '' or tmp['linfo3+2'] ~= '' then linfo4_3_2_fmt = mw.ustring.format(i18n.html['row-collapsible-left-linfo4+3+2-fmt'], tmp['linfo4'], tmp['linfo3+2']) end
result = result .. mw.ustring.format(i18n.html['row-general-fmt'], mw.ustring.format(i18n.html['row-collapsible-left-button-fmt'], i18n.html['row-collapsible-left-button-width'], q.text_width[1]),
'1', q.text_width[2], linfo4_3_2_fmt, q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp['rowProp']['bg'], tmp['cells'], '', '', '', '1', '', '', mw.ustring.format(i18n.html['row-rinfo4-fmt'], '', ''))
else
if tmp['rinfo4'] ~= '' or tmp['rinfo2+3'] ~= '' then rinfo2_3_4_fmt = mw.ustring.format(i18n.html['row-collapsible-right-rinfo2+3+4-fmt'], tmp['rinfo2+3'], tmp['rinfo4']) end
result = result .. mw.ustring.format(i18n.html['row-general-fmt'], mw.ustring.format(i18n.html['row-linfo4-fmt'], q.text_width[1], tmp['linfo4']),
'1', q.text_width[2], tmp['linfo3+2'], q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp['rowProp']['bg'], tmp['cells'], q.rinfo1_pad, q.text_width[4], tmp['rinfo1'],
'1', q.text_width[5], rinfo2_3_4_fmt, mw.ustring.format(i18n.html['row-collapsible-right-button-fmt'], i18n.html['row-collapsible-right-button-width'], q.text_width[6]))
end
if replace ~= '' then
if q.isKeyword(rows[i + 1], i, rows, true) then return result .. formaterror('collapsible-block-no-replacement') end--a plain row needed for replacement
table.remove(rows, i)
tmp = row(rows[i], true, nil)
local padding, right = i18n.html['row-collapsible-right-button-width'] .. ' 0 0', ''
if q.rinfo1_pad == '' then padding = '0 0 ' .. i18n.html['row-collapsible-left-button-width'] ; right = 'right:0px;' end
result = result .. mw.ustring.format(i18n.html['row-collapsible-replace-begin-fmt'], padding, right, props['bg-replace'])
linfo4_3_2_fmt = '' ; rinfo2_3_4_fmt = ''
if q.rinfo1_pad == '' then
if tmp['linfo4'] ~= '' or tmp['linfo3+2'] ~= '' then linfo4_3_2_fmt = mw.ustring.format(i18n.html['row-collapsible-left-linfo4+3+2-fmt'], tmp['linfo4'], tmp['linfo3+2']) end
result = result .. mw.ustring.format(i18n.html['row-general-fmt'], mw.ustring.format(i18n.html['row-linfo4-fmt'], '', ''), '1', q.text_width[2], linfo4_3_2_fmt,
q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp['rowProp']['bg'], tmp['cells'], '', '', '', '1', '', '', mw.ustring.format(i18n.html['row-rinfo4-fmt'], '', ''))
else
if tmp['rinfo4'] ~= '' or tmp['rinfo2+3'] ~= '' then rinfo2_3_4_fmt = mw.ustring.format(i18n.html['row-collapsible-right-rinfo2+3+4-fmt'], tmp['rinfo2+3'], tmp['rinfo4']) end
result = result .. mw.ustring.format(i18n.html['row-general-fmt'], mw.ustring.format(i18n.html['row-linfo4-fmt'], q.text_width[1], tmp['linfo4']), '1', q.text_width[2],
tmp['linfo3+2'], q.linfo1_pad, q.text_width[3], tmp['linfo1'], tmp['rowProp']['bg'], tmp['cells'], q.rinfo1_pad, q.text_width[4], tmp['rinfo1'], '1', q.text_width[5],
rinfo2_3_4_fmt, mw.ustring.format(i18n.html['row-rinfo4-fmt'], '', ''))
end
result = result .. i18n.html['row-collapsible-replace-end-fmt']
end
return result
end
q['endCollapsible'] = function(params, i, rows)
if q.collapsibles > 0 then
q.collapsibles = q.collapsibles - 1
return i18n.html['row-collapsible-end-fmt']
else
return formaterror('collapsible-block-not-open')
end
end
q['colspan'] = function(params, i, rows)
if params[2] == 'end' then return '' end
local tmp, j, nrows, props = {}, 0, tonumber(params[2]), properties(table.concat(params, '-', 3))
if nrows ~= 0 then table.remove(rows, i) end
if nrows == nil then nrows = #rows - i + 1 end
while j < nrows and i <= #rows do
j = j + 1
if rows[i] == '-colspan-end' then
j = nrows
else
table.insert(tmp, rows[i])
end
if nrows ~= j or i == #rows then table.remove(rows, i) end
end
if j < nrows then j = formaterror('colspan-less-rows-than-set',j) else j = '' end
return mw.ustring.format(i18n.html['colspan-fmt'], j, props['bg'] or '', props['align'] or '', props['style'] or '', mw.getCurrentFrame():preprocess(table.concat(tmp, '\n')))
end
q['filler'] = function(params, i, rows)
local tmp, height = table.concat(params, '-', 3), '5px'
if #params < 3 or tmp == '' then return formaterror('parameter-missing') end--TODO: указать имя нужного параметра.
if params[2] ~= '' then height = params[2] end
return row(tmp, nil, height)
end
function p.RGBbyCode(frame)
return RGBbyCode(mw.text.trim(frame.args[1] or ''))
end
local function localroute(pattern,ptw,pbg)
local tmp = {}
if mw.text.trim(pbg) ~= '' then q.bg = pbg end
tmp = mw.text.split(mw.text.trim(ptw), ',')
if #tmp == 6 then
for i = 1, 6 do
if tmp[i] ~= '' then
if tonumber(string.sub(tmp[i],-1)) then
q.text_width[i] = 'width:' .. tmp[i] .. 'px;'
else
q.text_width[i] = 'width:' .. tmp[i] .. ';'
end
end
end
if tmp[4] == '' and tmp[5] == '' and tmp[6] == '' then
q.rinfo1_pad = ''--padding for rinfo1 column = 0, not 3px
elseif tmp[1] == '' and tmp[2] == '' and tmp[3] == '' then
q.linfo1_pad = ''
end--padding for linfo1 column = 0, not 3px
elseif #tmp == 3 then
for i = 1, 3 do
if tmp[i] ~= '' then
if tonumber(string.sub(tmp[i],-1)) then
q.text_width[i + 3] = 'width:' .. tmp[i] .. 'px;'
else
q.text_width[i + 3] = 'width:' .. tmp[i] .. ';'
end
end
end
q.linfo1_pad = ''
elseif #tmp == 1 and tmp[1]~='' then
if tonumber(string.sub(tmp[1],-1)) then
q.text_width[5] = 'width:' .. tmp[1] .. 'px;'
else
q.text_width[5] = 'width:' .. tmp[1] .. ';'
end
q.linfo1_pad = ''
end
tmp = {}
local index = 0
local rows = {}
for item in pattern:gmatch('([^\n]*)\n?') do
item = mw.text.trim(item)
if item ~= '' then
index = index + 1
rows[index] = item
end
end
if index == 0 then return formaterror('parameter-missing') end
for i, v in ipairs(rows) do
local keyword = q.isKeyword(v, i, rows)
if type(keyword) ~= "string" then
table.insert(tmp, row(v, nil, nil))
else
table.insert(tmp, keyword)
end
end
if q.collapsibles > 0 then table.insert(tmp, formaterror('collapsible-block-not-closed') .. q['endCollapsible']()) end
if q.collapsibles ~= -1 then
if q.rinfo1_pad == '' then
q.text_width[1] = q.text_width[1] .. 'min-width:' .. i18n.html['row-collapsible-left-button-width'] .. ';'
else
q.text_width[6] = q.text_width[6] .. 'min-width:' .. i18n.html['row-collapsible-right-button-width'] .. ';'
end
end
-- ↓ empty row to set column widths; ↑ if q.collapsibles ≠ -1 and there are collapsible sections, leftmost or rightmost column should be wide enough to accomodate the button
table.insert(tmp, mw.ustring.format(i18n.html['empty-row-fmt'], q.text_width[1], q.text_width[2], q.linfo1_pad, q.text_width[3], q.rinfo1_pad, q.text_width[4], q.text_width[5], q.text_width[6]))
return table.concat(tmp)
end
function p.route(frame)
local rows = frame.args.pattern or ''
local tw = frame.args['text-width'] or ''
local bg = frame.args.bg or ''
return localroute(rows,tw,bg)
end
local getArgs
function p._infobox(args)
args[1] = args[1] or args.map or ''
args.tw = args.tw or args['text width'] or args['text-width'] or ''
args['title color'] = args['title color'] or args['title-color'] or '#fff'
args['title bg color'] = args['title bg color'] or args['title-bg'] or '#27404E'
args.legend = args.legend or ''
local navbar = require('Module:Navbar').navbar
local navtable = {}
args.navbar = args.navbar or args.tnavbar
if args.navbar then
navtable = {args.navbar, mini = true}
args.navbar = navbar(navtable)
else
args.navbar = ''
end
local result = ''
if args.inline then result = result..' \n' end
result = result..'{|'
args.collapse = args.collapse or args.collapsed
if args.collapsible == 'no' or args.collapsible == '0' then
args.collapsible = '0'
else
result = result .. 'class="collapsible '
if args.collapse then result = result .. 'collapsed' end
result = result .. '" '
end
args.float = args.float or 'right'
if args.float == 'right' then
args.margin = 'margin-left:1em;'
elseif args.float == 'left' then
args.margin = 'margin-right:1em;'
else
args.margin = ''
end
if args.inline then
args.inline2 = 'float:none;width:100%;margin:0;border:none;'
args.fontsize = '100%'
else
args.inline2 = 'box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); -moz-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2); -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 1px 5px 0 rgba(0, 0, 0, 0.12), 0 3px 1px -2px rgba(0, 0, 0, 0.2);'
args.fontsize = '85%'
end
args.bg = args.bg or '#F9F9F9'
args.style = args.style or ''
result = result .. 'cellspacing="0" cellpadding="0" style="float:' .. args.float .. ';clear:' .. args.float .. ';margin-top:0;margin-bottom:1em;' .. args.margin .. ';empty-cells:show;border-collapse:collapse;font-size:' .. args.fontsize .. ';background:' .. args.bg .. ';' .. args.inline2 .. args.style .. '"'
args.title = args.title or ''
if args.inline or args.title == 'no' or args.title == '0' then
else
result = result .. '\n! style="color:' .. args['title color'] .. ';background-color:' .. args['title bg color'] .. ';text-align:center;padding:5px"|'
if args['navbar pos'] then
result = result .. '<div>'
else
if args.navbar ~= '' then
navtable.brackets = true
navtable.style = 'float:left;margin-right:5px;white-space:nowrap'
navtable.fontstyle = 'font-size:115%;color:' .. args['title color']
args.navbar = navbar(navtable) .. '<div style="margin-left:55px">'
else
args.navbar = '<div>'
end
result = result .. args.navbar
end
result = result .. '<div style="white-space:nowrap;'
if args.collapsible == '0' and (args['navbar pos'] or args.navbar == '<div>') then
else
result = result .. 'margin-right:55px;'
if args['navbar pos'] or args.navbar == '<div>' then
result = result .. 'margin-left:55px;'
end
end
result = result .. 'font-size:115%;">' .. args.title .. '</div></div>'
end
args.top = args.top or args['on top']
if args.top then
result = result .. '\n|-\n|style="padding:0px 5px;text-align:center"|' .. args.top
end
result = result .. '\n|-\n|style="line-height:normal;padding:4px 5px"|'
if args.navbar ~= '' and args['navbar pos'] == '1' then
result = result .. '<div style="float:left;padding-right:5px">' .. args.navbar .. '</div>'
end
args.legend2 = args.legend:lower()
if args.legend2 == 'no' or args.legend2 == '0' then
else
local legtable = {['water']={'canal','water','waterway'},['foot']={'foot','footpath','walkway'}}
for k, v in pairs(legtable) do
for _, name in ipairs(v) do
if args.legend2 == name then args.legend2 = k end
end
end
if args.legend2 == 'water' then args.legend = '[[Template:Waterways legend'
elseif args.legend2 == 'foot' then args.legend = '[[Template:Trails legend'
elseif args.legend2 == 'bus' then args.legend = '[[Template:Bus route legend'
elseif args.legend2 == 'track' then args.legend = '[[Template:Railway track legend'
elseif args.legend ~= '' then args.legend = '[[' .. args.legend
else args.legend = '[[Template:Railway line legend'
end
if args['legend alt'] then
args.legend = args.legend .. '|' .. args['legend alt'] .. ']]'
else
args.legend = args.legend .. '|Legend]]'
end
result = result .. '<div style="text-align:right;font-size:90%;">' .. args.legend .. '</div>'
end
result = result .. '\n|-\n|style="padding:0px"|\n{|cellpadding="0" cellspacing="0" class="nogrid" style="padding:0px;border:0px;background:transparent;white-space:nowrap;line-height:1.2;font-size:110%;margin:'
if args.inline then
result = result..'auto'
else
result = result..'0px 6px 6px'
end
result = result..'"\n' .. localroute(args[1],args.tw,args.bg) .. '\n|}'
args.bottom = args.bottom or args.footnote
if args.bottom then
result = result .. '\n|-\n|style="line-height:normal;text-align:right;padding:0px 5px 5px"|' .. args.bottom
end
if args.navbar ~= '' and args['navbar pos'] == '2' then
result = result .. '\n|-\n|style="line-height:normal;padding:0px 5px 3px;text-align:center"|' .. args.navbar .. '</div>'
end
return result .. '\n|}'
end
function p.infobox(frame)
if not getArgs then
getArgs = require('Module:Arguments').getArgs
end
return p._infobox(getArgs(frame))
end
local function pre_block(text)
-- Pre tags returned by a module do not act like wikitext <pre>...</pre>.
return '<pre>' ..
mw.text.nowiki(text) ..
(text:sub(-1) == '\n' and '' or '\n') ..
'</pre>\n'
end
function p.convertbs(frame)
local org = mw.text.unstripNoWiki(frame.args[1]) or 'Paste legacy RDT markups between the nowiki tags'
local res = org
res = string.gsub(res, '{{[Bb][Ss]%-?map', '{{Routemap') -- "%-" is an escape for hyphen which is used as "between" in pattern.
res = string.gsub(res, '{|{{[Rr]ailway line header}}', '{{Routemap')
res = string.gsub(res, '{{[Bb][Ss]%-header%d?|', '{{safesubst:BS-header/safesubst|') -- "%d?" means optional digit in case use of variant template like BS-header3.
res = string.gsub(res, '{{[Bb][Ss]%-table%d?}}', '|map=')
res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)|', '{{safesubst:BS%1%2/safesubst|')
res = string.gsub(res, '{{[Bb][Ss](%d?)(%d?)%-2|', '{{safesubst:BS%1%2-2|')
res = string.gsub(res, '{{[Bb][Ss]km|', '{{BSkm{{!}}')
res = string.gsub(res, '{{[Bb][Ss]to|', '{{BSto{{!}}')
res = string.gsub(res, '{{[Bb][Ss]split|', '{{BSsplit{{!}}')
res = string.gsub(res, '{{[Bb][Ss]cvt|', '{{BScvt{{!}}')
res = string.gsub(res, '|}\n|}', '}}') -- Replace ending of Railway line header map setup.
res = string.gsub(res, '{{[Bb][Ss]%-colspan}}\n{{safesubst', '{{safesubst') -- BS-colspan is unncessary and would cause error in Routemap.
res = string.gsub(res, '{{[Bb][Ss]%-colspan}}\n%-%-%-%-', '-colspan-2\n----')
res = string.gsub(res, '{{[Bb][Ss]%-colspan}}(.?)', '-colspan-1\n%1')
return "\n'''Safe substitution''':\n" .. pre_block(res) .. "'''''Original''''':\n" .. pre_block(org)
end
return p
--[[for testing in console:
print(p.route({['args={['text-width='',['pattern=[=[
STR
STR]=]}}))
]]