Модуль:Ibox
Уҡыу көйләүҙәре
Для документации этого модуля может быть создана страница Модуль:Ibox/doc
--Some local aliases
local lang, unw, ufind, uboff =
mw.language.getContentLanguage(), mw.text.unstripNoWiki, mw.ustring.find, mw.ustring.byteoffset
local expr, lfn, trim = mw.ext.ParserFunctions.expr, lang.formatNum, mw.text.trim
local function expnum(n, pom, dot)--good HTML exponential notation producer(number,digits,power of 10)
return (dot
and table.concat{lfn(lang, tonumber((pom and "%."..pom.."f" or "%f"):format(n/10^dot))),"·10<sup>",dot,"</sup>"}
or (pom and "%."..pom.."g" or "%g"):format(n):gsub('e([+-]?%d+)',
function(o)return ("·10<sup>%i</sup>"):format(o)end
):gsub('^([%d.]+)',function(p) return lfn(lang, tonumber(p)) end)
):gsub('-','−')
end
local vfinter = {["["]=function(s)return tonumber(trim(s)) end,["{"]=tostring,["("]=function(s)
s=trim(s)
return tonumber(s) or s
end}--functions for getting variables. Note that {} by default does not trim.
local function getsym(tf,l,n,st)--gets first defined in table l symbol of sequence st where last one is fallback
local d
for i = 1, n-1 do
d=l[tf(st[i])]
if d~=nil then
return d
end
end
if n>1 then return st[n] end
end
local term={['(']=')', ['{']='}', ['[']=']'}
-- \A \L...\E \l \N...\E \n \Q...\E \R...\E \s \T \t \U...\E \u \Z
local function mp(s, args, func)
local n, nn, tm, hv, cm, rm = 1--position, new position, truncate mode, byte after $, case mode, raw number mode
local pf--Function which does main parsing work
local pp, sm, n, r = 1, 0, 1, {}--previous position, space mode, r insert position, result table to concat
if s:match("\\[NQ]") then-- We must escape \Q...\E & unstrip all needed nowikis before we start with the rest
s = s:gsub("`", "``"):gsub([[\([^NQ\])]], "!`!%1"):gsub([[\\]],"!`!!`!"):gsub("\\Q(.-)!`!E",
function(ch)return ch:gsub("[$()%[%]{}:\\]","\\%1"):gsub("!`!",[[\\]]):gsub("\\$","!`!") end
):gsub([[\N(.-)!`!E]], function(ch) return unw(ch) end):gsub("!`!","\\"):gsub("``","`")
end
pf = function(t,stopf)--Returns result of expression in s starting at n and terminated by symbol t and shifts n after the symbol
local p, c, ch, chn
repeat
p, chn, c, ch = s:find('(['..t..'\\$:])(.?)',pp)--find special symbol, argument end or terminator
if not c or ch=='' then --final special symbol doesn't count
insprev(#s)
break
end
if c==[[\]] then--escaped symbol
(BSactions[ch] or function()
r[n] = ch
n=n+1
end)()--?
elseif c=="$" then--var or function
local cmd,nsym,i,f
if term[ch] then--the name is in some brackets
nsym, cmd = pf(term[ch])-- Could we have some stop-function here?
if term[s[p]] then-- function
f = getsym(vfinter[ch],func,nsym,cmd)
else--var
end
elseif ch=='$' then--call var or function by name
end
end
until false
end
local function argfinish(z)--argument finished by symbol z
local t,fn,argn = unpack(fs[fc],1,3)
if argn~=n-1 then--convert to single string
for i = argn, n-1 do
if not rm and r[fn]~=expr and type(r[i]) == 'number'
then r[i] = lfn(lang,r[i])
elseif r[i] == nil then r[i] = ''
end
end
r[argn] = table.concat(r,'',argn,n-1)--Record joined argument
end
n = argn+1--Shift insert position
if z==")" then--execute function (including $(...))
r[fn] = r[fn](unpack(r,fn+1,n-1))
fc = fc-1
n = fn+1
elseif z=="}" then--get string property (including ${...}, $x{...})
local rfn, m = r[fn]
for j = fn+1, n-1 do
m = rfn[tostring(r[j])]
if m ~= nil then break end
end
r[fn] = m
fc = fc-1
n=fn+1
elseif z=="]" then--get numeric property (including $[...], $x[...])
local rfn, m = r[fn]
for j = fn+1, n-1 do
m = rfn[tonumber(r[j])]
if m ~= nil then break end
end
r[fn] = m
fc = fc-1
n=fn+1
elseif z==':' then--next argument
fs[fc][3] = n
else--Dename?
--TODO
end
end
local function insprev(pe)--Insert previous plain chunk into r
if pp<=pe then--chunk unempty
local ch, sp, i, sep = s:sub(pp,pe)
if cm then
-- NOTE: these functions are not stripmarker-safe.
-- mw.getCurrentFrame():callParserFunction(cm, ch) is safe but slower, just let's do without it.
ch = lang[cm](lang, ch)
if cm=='ucfirst' or cm=='lcfirst' then cm=nil end
end
--Processing arguments and functions borders
if hv then
ch = hv..ch
hv = nil
sp = uboff(ch, ufind(ch, '([^%a%d_])'))--or who knows a faster way?
sep = nil
else
sp, i, sep = ch:find('['..fs[fc][1]..':]')--move argfinish inside?
end
--First subchunk may be affected by \Z
if sp then
local ch1 = ch:sub(1,sp-1)
if sm~=0 and ch1:match("^%s*$") then--clear spaces
n = sm
sm = 0
else
r[n] = ch1
n=n+1
end
else
if not ch:match("^%s*$") then sm=0 end
r[n] = ch
n = n+1
end--Not truncate if non-spaces after
end
end
local BSactions ={--TODO: put out of mp for quick multiple calls? How to handle locals?
A=function()if table.concat(r,'',fs[fn][3],n-1):match"^%s+$" then
n=fs[fn][3]
end; sm=0 end,--If only spaces before, removes them
L=function()cm='lc' end,--convert all characters to lower
E=function()cm=nil; rm=nil end,--cancels all special modes
l=function()cm='lcfirst'end,--convert next charater to lower
n=function()r[n] = "\n"; n=n+1 end,--newline
R=function()rm=true end,--Raw numbers mode
s=function()r[n] = " "; n=n+1 end,--non-breaking space
t=function()r[n] = "\t"; n=n+1 end,--tabulation
U=function()cm="uc" end,--convert all characters to upper
u=function()cm="ucfirst" end,--convert next character to upper
Z=function()sm=n end--Truncate forward at this argument if all the following are spaces
}
for cc, c, p in s:gmatch"([$\\])(.)()" do
insprev(p-2)
if cc=="\\" then
BSactions[c]()
elseif cc=='$' then
if c:match"[%[%{]" then--get name of a scalar or non-scalar
r[n]=function(...)
local args, noa = {...}, select('#', ...)
end
end
elseif cc==term then
break
elseif cc==sep then--TODO: multiple values
end
end
return table.concat(r), cm, nm
end
return {
_miniparser = mp,
_expnum = expnum,
infobox = function(frame)
local cfg, pframe = frame.args, frame:getParent()
local args = pframe.args
local box = mw.html.create("table"):attr{class = 'infobox', style=cfg["стиль_тела"]}:addClass(cfg["класс_тела"])
local v
local function td2(n,s,f)
v = cfg[n]
if v and v ~= "" then
box:tag('tr')
box:tag('td'):attr{colspan = "2",
class=cfg["класс_"..n] or f and cfg["класс_"..f],
style=s..cfg["стиль_"..n] or f and cfg["стиль_"..f]
}:wikitext(v)
end
end
v = cfg["название"]
if v and v ~= "" then
box:tag('caption'):attr{class=cfg["класс_названия"], style=cfg["стиль_названия"]}:wikitext(v)
end
td2("вверху", "text-align:center; font-size: 125%; font-weight: bold; ")
td2("вверху2", "text-align:center; font-style: oblique; ")
--image, lines: TODO
td2("внизу", "text-align:center; ")
td2("внизу2", "text-align:center; ", "внизу")
td2("внизу3", "text-align:center; ", "внизу")
--navbar
box:tag('tr')
box:tag('td'):attr{colspan="2", style="text-align:right"}:wikitext(require("Module:Navbar")._navbar{pframe.getTitle():gsub("^.*:","")})
return tostring(box)
end
}