Module:Routemap: Difference between revisions
Appearance
Content deleted Content added
comments of convertbs |
No edit summary |
||
Line 565: | Line 565: | ||
res = string.gsub(res, '{{%a%a%-header%d?|', '{{safesubst:BS-header/safesubst|') -- "%d?" means optional digit in case use of variant template like BS-header3. |
res = string.gsub(res, '{{%a%a%-header%d?|', '{{safesubst:BS-header/safesubst|') -- "%d?" means optional digit in case use of variant template like BS-header3. |
||
res = string.gsub(res, '{{%a%a%-table%d?}}', '|map=') |
res = string.gsub(res, '{{%a%a%-table%d?}}', '|map=') |
||
res = string.gsub(res, '{{%a%a|', '{{safesubst: |
res = string.gsub(res, '{{%a%a|', '{{safesubst:BS1/safesubst|') |
||
res = string.gsub(res, '{{%a%a(%d)|', '{{safesubst:BS%1|') |
res = string.gsub(res, '{{%a%a(%d)|', '{{safesubst:BS%1/safesubst|') |
||
res = string.gsub(res, '{{%a%a(%d)(%d)|', '{{safesubst:BS%1%2|') |
res = string.gsub(res, '{{%a%a(%d)(%d)|', '{{safesubst:BS%1%2/safesubst|') |
||
res = string.gsub(res, '{{%a%a%-2|', '{{safesubst:BS-2|') |
res = string.gsub(res, '{{%a%a%-2|', '{{safesubst:BS-2/safesubst|') |
||
res = string.gsub(res, '{{%a%a(%d)%-2|', '{{safesubst:BS%1-2|') |
res = string.gsub(res, '{{%a%a(%d)%-2|', '{{safesubst:BS%1-2/safesubst|') |
||
res = string.gsub(res, '{{%a%a(%d)(%d)%-2|', '{{safesubst:BS%1%2-2|') |
res = string.gsub(res, '{{%a%a(%d)(%d)%-2|', '{{safesubst:BS%1%2-2/safesubst|') |
||
res = string.gsub(res, '{{%a%akm|', '{{BSkm{{!}}') |
res = string.gsub(res, '{{%a%akm|', '{{BSkm{{!}}') |
||
res = string.gsub(res, '{{%a%ato|', '{{BSto{{!}}') |
res = string.gsub(res, '{{%a%ato|', '{{BSto{{!}}') |
Revision as of 11:57, 4 June 2016
![]() | This module is rated as ready for general use. It has reached a mature form and is thought to be relatively bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other Wikipedia resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing. |
![]() | This Lua module is used on approximately 27,000 pages and changes may be widely noticed. Test changes in the module's /sandbox or /testcases subpages, or in your own module sandbox. Consider discussing changes on the talk page before implementing them. |
![]() | Transwikiing this module requires TemplateStyles, Module:Navbar and Module:Color contrast. |
Related pages |
---|
![]() | This module depends on the following other modules: |
This module handles the {{Routemap}}, {{BSsplit}}, {{BSto}}, {{BScvt}}, {{BSsrws}}, {{RoutemapRoute}} and {{RoutemapRouteIcon}} templates. For usage instructions, see the respective templates' pages.
For sandbox test results, see Template:Routemap/testcases (purged) and Template:BSsplit/testcases (purged).
Tracking categories are at Category:Routemap tracking categories.
To do
- Make it easier to change sizes
- Long-term: Add support for merging and splitting table cells
- Add a link to where the TemplateStyles are defined
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"] = '\
|[[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"] = '\
|<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"|',
["row-linfo4-fmt"] = '\
|style="padding-right:3px;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="padding-left:3px;text-align:right;%s"|<span style="font-size:90%%;">%s</span>',-- parameters:rinfo4-width, rinfo4
["row-general-fmt"] = '\
|-%s\
|colspan="%s" style="text-align:right;%s"|%s\
|style="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"\
|-%s\
|}</center>\
|style="text-align:right;padding:0 %s;%s"|<span style="font-size:90%%;">%s</span>\
|colspan="%s" style="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"] = '\
|-\
|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:none !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="padding:0 3px 0 1px;text-align:left;"| <span style="font-size:90%%;">%s</span>\
|style="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="text-align:left"| %s\
|style="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"] = '\
|-\
|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'
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, '{{%a%a%-map', '{{Routemap') -- "%-" is an escape for hyphen which is used as "between" in pattern.
res = string.gsub(res, '{|{{%aailway line header}}', '{{Routemap') -- string.gsub cannot ignore letter case of specific alphabet in pattern, hence "BS" is replaced by "%a%a" as "any alphabet".
res = string.gsub(res, '{{%a%a%-header%d?|', '{{safesubst:BS-header/safesubst|') -- "%d?" means optional digit in case use of variant template like BS-header3.
res = string.gsub(res, '{{%a%a%-table%d?}}', '|map=')
res = string.gsub(res, '{{%a%a|', '{{safesubst:BS1/safesubst|')
res = string.gsub(res, '{{%a%a(%d)|', '{{safesubst:BS%1/safesubst|')
res = string.gsub(res, '{{%a%a(%d)(%d)|', '{{safesubst:BS%1%2/safesubst|')
res = string.gsub(res, '{{%a%a%-2|', '{{safesubst:BS-2/safesubst|')
res = string.gsub(res, '{{%a%a(%d)%-2|', '{{safesubst:BS%1-2/safesubst|')
res = string.gsub(res, '{{%a%a(%d)(%d)%-2|', '{{safesubst:BS%1%2-2/safesubst|')
res = string.gsub(res, '{{%a%akm|', '{{BSkm{{!}}')
res = string.gsub(res, '{{%a%ato|', '{{BSto{{!}}')
res = string.gsub(res, '{{%a%asplit|', '{{BSsplit{{!}}')
res = string.gsub(res, '{{%a%acvt|', '{{BScvt{{!}}')
res = string.gsub(res, '|}\n|}', '}}') -- Replace ending of Railway line header map setup.
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]=]}}))
]]