local i18n = {
errors = {
["parameter-missing"] = "缺失參數",
["collapsible-block-not-closed"] = "摺疊部分未封閉",
["collapsible-block-not-open"] = "摺疊部分無法展開可能是由於多餘的關閉命令",
["too-many-parameters"] = "參數過剩",
["no-icons"] = "未有指定圖標",
["colspan-too-many-to-span"] = "colspan無法整合字串",
["unknown-keyword"] = "不明參數«%s»",
["invalid-keyword-at-position"] = "錯誤位置導致參數«%s»無效",
["no-collapsible-block-and-alt-syntax"] = "不兼容摺疊功能"
},
misc = {
["keyword-any"] = "''任意''"
},
["error-categories"] = {
default = '[[Category:Wikipedia:條目存在參數錯誤的線路圖]]'
--["parameter-missing"] = '[[Category:Wikipedia:條目存在缺失參數的線路圖]]'--特定錯誤分類
},
html = {
["cell-icon-fmt"] = '\
|style="width:20px"|[[File:BSicon_%s.svg|20px|link=%s|alt=]]',
["cell-overlapicon-fmt"] = '<div style="position:absolute;left:0px;top:0px;padding:0">[[File:BSicon_%s.svg|20px|link=%s|alt=]]</div>',
["cell-icon-fmt-with-overlap"] = '\
|style="width:20px"|<div style="position:relative;width:20px">\
%s[[File:BSicon_%s.svg|20px|link=|alt=]]</div>',
["row-info3-fmt"]='<span style="font-size:90%%;padding-left:3px">%s</span>',
["row-info4-fmt"]='<div style="font-size:90%%;padding-left:3px;float:right">%s</div>',
["row-general-fmt"] = '\
|-\
|style="padding:0;white-space:nowrap;background-color:%s"|<center>\
{|cellspacing="0" cellpadding="0" style="background-color:transparent;line-height:0px !important"\
|-%s\
|}</center>\
|style="text-align:right;vertical-align:middle;padding:0 3px;font-size:80%%"|%s\
|colspan="2" style="vertical-align:middle;text-align:left;width:%s"|%s',
["row-collapsible-begin-fmt"] = '\
|-\
|colspan="5" style="padding:0 !important;white-space:nowrap;background-color:%s"|\
{|class="mw-collapsible mw-%s autocollapse" cellpadding="0" cellspacing="0" style="background-color:transparent;line-height:1.2em !important;padding:0 !important;align:left !important;margin:none !important;width:100%% !important"\
|-\
|style="padding:0 !important;white-space:nowrap;text-align:center !important;width:0px !important"|\
{|cellspacing="0" cellpadding="0" style="background-color:transparent;float:none !important;margin:auto !important;width:auto !important;line-height:0px !important"\
|-%s\
|}\
|style="text-align:right;vertical-align:middle;padding:0 3px;font-size:90%%;border: 0px !important" |%s\
!style="text-align:left;vertical-align:middle;white-space:nowrap;width:100%%;padding-right:3px;border:0px !important" colspan="2" |%s',
["row-collapsible-replace-begin-fmt"] = '\
|-\
|style="text-align:left;padding:0;white-space:nowrap"|\
<div style="position:relative">\
{|align="left" cellspacing="0" cellpadding="0" style="position:absolute;bottom:0px;background-color:#f9f9f9"\
|-%s\
|}</div>\
|style="text-align:left;padding:0;white-space:nowrap;vertical-align:middle"|\
<div style="position:relative">\
{|align="left" cellspacing="0" cellpadding="0" style="position:absolute;bottom:0px;vertical-align:middle;bottom:0px;top:-15px;background-color:#f9f9f9;line-height:130%%"\
|style="text-align:right;vertical-align:middle;padding:0 3px;font-size:90%%"|%s\
!style="text-align:left;vertical-align:middle;white-space:nowrap;width:100%%;padding-right:3px;min-width:10em" colspan="2"|%s\
|}</div>',
["row-alt-fmt"] = '\
|-\
|style="text-align:right;vertical-align:middle;padding-right:3px;width:%s"|%s\
|style="padding:0;white-space:nowrap;background-color:%s;text-align:center !important;width:0px"|\
{|cellspacing="0" cellpadding="0" style="background-color:transparent;float:none !important;margin:auto !important;width:auto !important;line-height: 0px !important;padding:0 !important"\
|-%s\
|}\
|style="text-align:left;vertical-align:middle;width:%s"|<span style="padding-left:3px">%s</span>',
["row-alt-left-note-fmt"] = '<span style="font-size:90%%;padding-right:3px">%s</span>',
["row-alt-right-note1-fmt"] = ' <span style="font-size:90%%">%s</span>',
["row-collapsible-end"] = '\n|}',
["colspan-fmt"] = '%s\n|-\n|colspan="4" |\n%s'
}
}
local function formaterror(key,param)
local result=mw.ustring.format('\n|-\n|<span class="error">%s</span>',mw.ustring.format(i18n.errors[key]or tostring(key)..' %s',
tostring(param or '')))
title=mw.title.getCurrentTitle()
if mw.site.namespaces[title.namespace].isContent then result=result..(i18n['errors-categories'][key]or
i18n['errors-categories'].default or '')end
return result
end
local p,q={},{}
-- Compatibility: Lua-5.0
-- Source: http://lua-users.org/wiki/SplitJoin
-- Author: http://lua-users.org/wiki/PhilippeLhoste
local function Split(str, delim, maxNb)
if delim==nil or delim=='' then error('bad argument #2 to \'Split\' (non-empty string expected), got '..type(delim),1)end
if str=='' or string.find(str, delim) == nil then return{ str }end
if maxNb == nil or maxNb < 1 then
maxNb = 0 -- No limit
end
local result = {}
local pat = "(.-)" .. delim .. "()"
local nb = 0
local lastPos
for part, pos in string.gfind(str, pat) do
nb = nb + 1
result[nb] = part
lastPos = pos
if nb == maxNb then break end
end
-- Handle the last field
if nb ~= maxNb then
result[nb + 1] = string.sub(str, lastPos)
end
return result
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=Split(overlapIcons[#overlapIcons],'!@',2)
overlapIcons[#overlapIcons]=tmp[1]
if #tmp==2 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=Split(icon,'!@',2)
icon=mw.text.trim(tmp[1])
if #tmp==2 then link=tmp[2] end
return mw.ustring.format(i18n.html['cell-icon-fmt'],icon,link)
end
local function row(pattern,collapse)
--Row handling. Each row looks like the following:
--(icon pattern)~~info 1~~info 2~~note 1~~note 2(row properties)
--where "(row properties)" is a combination of properties with following syntax:
--!~property name=value
--Currently only "bg" (background color) and "width" are used for regular — not collapsible — rows.
local rowProp={
['bg'] = 'transparent',
['width'] = 'auto',
qqx={}
}
local info,icons,color={}
local cells,overlapIcons,tmp={},{},Split(pattern,'~~',5)
if #tmp>1 then rowProp.qqx=Split(tmp[#tmp],'!~')end
if #rowProp.qqx>1 then
tmp[#tmp]=rowProp.qqx[1]
table.remove(rowProp.qqx,1)
for i,v in ipairs(rowProp.qqx)do if v~='' then
local t=Split(v,'=',2)
rowProp[t[1]]=t[2]or ''
end
end
end
if #tmp>2 then
info[1]=tmp[2]or''
info[2]=tmp[3]or''
if #tmp>3 then info[2]=info[2]..mw.ustring.format(i18n.html['row-info3-fmt'],tmp[4])end
if #tmp>4 then info[2]=info[2]..mw.ustring.format(i18n.html['row-info4-fmt'],tmp[5])end
else--assume only info2 was provided.
info[1]=''
info[2]=tmp[2]or''
end
icons=Split(tmp[1],'\\')
for i,v in ipairs(icons)do
tmp=Split(v,'!~')
icons[i]=tmp[1]
table.remove(tmp,1)
table.insert(overlapIcons,tmp)
end
if #icons+#overlapIcons<1 then return formaterror('no-icons')end
info[1]=mw.getCurrentFrame():preprocess(info[1])--expand possible templates in info.
info[2]=mw.getCurrentFrame():preprocess(info[2])
for i,v in ipairs(icons)do table.insert(cells,cell(v,overlapIcons[i]))end
cells=table.concat(cells)
if type(collapse)=='string' then
return mw.ustring.format(i18n.html["row-collapsible-begin-fmt"],rowProp['bg'],collapse,cells,info[1],info[2])elseif collapse==true
then return mw.ustring.format(i18n.html['row-collapsible-replace-begin-fmt'],cells,info[1],info[2])
else return mw.ustring.format(i18n.html['row-general-fmt'],rowProp['bg'],cells,info[1],rowProp['width'],info[2])end
end
local function row2(pattern)--no collapsibles yet
--Row handling. Each row looks like the following:
--leftmost text! !(icon pattern)~~rightmost text~~note 1~~note2(row properties)
--where "(row properties)" is a combination of properties with following syntax:
--!~property name=value
--Currently used are "bg" (background color), "width-left" and "width-right".
local rowProp={
['bg'] = 'transparent',
['width-right'] = 'auto',
['width-left'] = 'auto',
qqx={}
}
local info,icons,color,left,right={}
local cells,overlapIcons,tmp={},{},Split(pattern,'! !',2)
if #tmp>1 then
left=tmp[1]
right=tmp[2]
else
left=''
right=tmp[1]or ''
end
tmp=Split(right,'~~',4)
if #tmp>1 then rowProp.qqx=Split(tmp[#tmp],'!~')end
if #rowProp.qqx>1 then
tmp[#tmp]=rowProp.qqx[1]
table.remove(rowProp.qqx,1)
for i,v in ipairs(rowProp.qqx)do if v~='' then
local t=Split(v,'=',2)
rowProp[t[1]]=t[2]or ''
end
end
end
if #tmp>1 then--parse right side.
info.right=tmp[2]
if #tmp>2 then info.right=info.right..mw.ustring.format(i18n.html['row-alt-right-note1-fmt'],tmp[3])end
if #tmp>3 then info.right=info.right..mw.ustring.format(i18n.html['row-info4-fmt'],tmp[4])end
else--assume only right text was provided.
info.right=tmp[2]or''
end
icons=Split(tmp[1],'\\')
for i,v in ipairs(icons)do
tmp=Split(v,'!~')
icons[i]=tmp[1]
table.remove(tmp,1)
table.insert(overlapIcons,tmp)
end
if #icons+#overlapIcons<1 then return formaterror('no-icons')end
tmp=Split(left,'~~',2)--parse left side.
if #tmp>1 then
info.left=tmp[2]--left note
info.left=mw.ustring.format(i18n.html['row-alt-left-note-fmt'],tmp[1])..info.left--left text
else--assume only left text was provided
info.left=tmp[1]or''
end
info.left=mw.getCurrentFrame():preprocess(info.left)--expand possible templates in info.
info.right=mw.getCurrentFrame():preprocess(info.right)
for i,v in ipairs(icons)do table.insert(cells,cell(v,overlapIcons[i]))end
cells=table.concat(cells)
return mw.ustring.format(i18n.html['row-alt-fmt'],rowProp['width-left'],info.left,rowProp['bg'],cells,
rowProp['width-right'],info.right)
end
q={'startCollapsible','collapsibleReplace','colspan',collapsible=0}
q.isKeyword=function(pattern,i,rows,justTest)
local tmp=Split(pattern,'-')
if #tmp<2 or tmp[2]=='' or tmp[1]>'' then
if justTest then return false else return nil end--not a valid keyword
end
table.remove(tmp,1)--delete first, empty part before "-"
if type(q[tmp[1]])=="function" and tmp[1]~='isKeyword' then--valid keyword
if justTest then return true else return q[tmp[1]](tmp,i,rows)end
else if justTest then return false else return formaterror('unknown-keyword',tmp[1])end
end
end
q['startCollapsible']=function(params,i,rows,alt)
table.remove(rows,i)
if alt then return formaterror('no-collapsible-block-and-alt-syntax')end
if i>#rows-3 then return formaterror('collapsible-block-not-closed')end--not enough lines to close the collapsible block
if q.isKeyword(rows[i],i,rows,true)then
return formaterror('invalid-keyword-at-position',i18n.misc['keyword-any'])end--no valid keywords that can follow "startCollapsible" yet
local param1,param2=params[2]or '',params[3]or 0--params[1] is the keyword name so all indices are shifted by one.
q.collapsible=q.collapsible+1
local result
if param1=='' then param1='collapsed' end
if param2~=0 then
result=row(rows[i],param1)
result=result..row(rows[i+1],true)
table.remove(rows,i)
return result
else return row(rows[i],param1)end
end
q['endCollapsible']=function(params,i,rows,alt)
if q.collapsible>0 then
q.collapsible=q.collapsible-1
return i18n.html['row-collapsible-end']
else return formaterror('collapsible-block-not-open')end
end
q['colspan']=function(params,i,rows,alt)
local tmp,j,param1={},0
if params[2]=='end' then return '<!-- -colspan-end -->' else param1=tonumber(params[2])end
table.remove(rows,i)
if param1==nil then param1=#rows-i+1 end
while j<param1 and i<=#rows do
j=j+1
local result=q.isKeyword(rows[i],i,rows)
if type(result)~="string" then table.insert(tmp,rows[i])elseif result=='<!-- -colspan-end -->' then
j=param1
else table.insert(tmp,result)end
if param1~=j or i==#rows then table.remove(rows,i)end
end
if j<param1 then j=formaterror('colspan-too-many-to-span') else j='' end
return mw.ustring.format(i18n.html['colspan-fmt'],j,mw.getCurrentFrame():preprocess(table.concat(tmp,'\n')))
end
function p.route(frame)
-- ВАЖНО: параметр «pattern» должен быть следующего вида:
-- иконки!~перекрывающая иконки\(ещё)\(если надо, то ещё и т. д.)~~время~~текст~~пояснение~~пояснение мелким шрифтом\n
-- (другая строка таблицы в этом формате)\n(и так далее)
-- ВАЖНО: если вам нужен текст слева от иконок, то параметр «pattern» должен быть следующего вида:
-- текст слева! !иконки!~перекрывающая иконка\(ещё)\(если надо, то ещё и т. д.)~~текст справа~~пояснение справа\n
-- (другая строка таблицы в этом формате)\n(и так далее)
local rows,tmp,alt,func={},{},false,row
rows=Split(frame.args['pattern'],'\n')
if mw.text.trim(table.concat(rows))=='' then return formaterror('parameter-missing')end
if frame.args['alt']=='1' then
func=row2
alt=true
end
for i,v in ipairs(rows)do
local keyword=q.isKeyword(v,i,rows,alt)
if type(keyword)~="string" then table.insert(tmp,func(v,nil))else table.insert(tmp,keyword)end
end
if q.collapsible>0 then table.insert(tmp,formaterror('collapsibe-block-not-closed')..q['endCollapsible']())end
return table.concat(tmp)
end
return p