Interested Article - Ibox

Документация
--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
}
Источник —

Same as Ibox