local navbar = require 'module:navbar'._navbar local hcreate = mw.html.create local luaon = require 'module:Luaon' local function index(t,paras) local result = t for i, k in ipairs(paras) do if not result then return nil end result = result[k] end return result end local function newindex(t,value,paras) local num = #paras local current = t for i,k in ipairs(paras) do if i == num then if type(current[k])~='table' then current[k] = value end return type(value)=='table' and current[k] or t else if type(current[k]) ~= 'table' then current[k] = {} end current = current[k] end end end local function getkeys(key,...) local t = {} for each in key:gmatch('[^%-]') do local num = tonumber(each) if not num then return nil end table.insert(t,num) table.insert(t,'list') table.insert(t,'content') end t[#t], t[#t-1] = nil -- Anyway no nil is ok for _,append in ipairs {...} do table.insert(t,append) end return t end local zes = {} local navbox = {} function zes.new(paras) local obj = {} local paras = paras or {} obj.args = paras.args or {} obj.data = paras.data or {} obj.level = paras.level or 0 obj.isChild = obj.level > 0 obj.root = paras.root obj.rootself = paras.rootself or obj return setmetatable(obj,{__index = navbox}) end local suffixes = { content = true, style = true, class = true } function navbox:checkItem(k, v, data) data = data or self.data if type(k) ~= 'string' then return end if k == 'name' then data.name = v return end local suffix = k:match('^list(%l+[%l%d%-%.]*)') if suffix and not suffixes[suffix] then self:checkItem(suffix,v,newindex(data,{},'list')) return end for _, prefix in ipairs { 'list','group','odd','even','title','body','single' } do if k:find '%d' then break end local suffix = k:match('^'..prefix..'(%l*)$') if suffix then if suffix == '' then suffix = 'content' end newindex(data,v,{prefix,suffix}) return end end local prefix, key, suffix = k:match '^([a-z]+)([0-9%.%-]+)([a-z]*)$' --2021.6.14:floatable -- 对于group和list,以及其他的类型,采取不同的数据加工方式 local isCell = (prefix=='group' or prefix=='list' or prefix=='single') if suffix=='' then suffix='content' end -- 这里的prefix可以是group,list -- 这里的suffix可以是空白、class或style -- 这里的key可以是1、2、3或1-2、1-4这样的数字或多重数字。 if not (suffix and suffixes[suffix]) then key, suffix = k:match '^list([%d%-%.]+)(%l+[%l%d%-%.]*)' end if not key then return end if not getkeys(key) then return end local keys1,keys2,keys3 = getkeys(key,'list','content'), getkeys(key,prefix,suffix), getkeys(key,'list','content',prefix,suffix) if not prefix then self:checkItem(suffix,v,newindex(data,{},keys1)) return elseif isCell then newindex(data,v,keys2) return else newindex(data,v,keys3) return end end function navbox:process() local args = self.args for k,v in pairs(args) do local key = k:match '^data(%d+)$' if key then local keys = getkeys(key,'list','content') if not keys then break end local data = luaon.decode(v) newindex(self.data,data,keys) end end for k,v in pairs(args) do v = mw.text.trim(v) if v ~= '' then self:checkItem(k,v) end end return self end function navbox:renderTitle(tArgs) local navbar = tArgs.navbar or '' local content = tArgs.content if not content then return end local style = tArgs.style local class = tArgs.class local root = self.root local row = root:tag 'tr':addClass('newstyle_navbox-row') row :tag ('th'):addClass 'newstyle_navbox-title' :attr('colspan',2) :wikitext(navbar) :wikitext(content) :addClass(class) :cssText(style) end function navbox:renderSingle(sArgs) local content = sArgs.content if not content then return end local rootdata = self.rootself.data local root = self.root local row = root:tag 'tr':addClass 'newstyle_navbox-row' row :tag 'td' :addClass 'newstyle_navbox-single' :attr('colspan',2) :wikitext(content) :addClass(index(rootdata,{'single','class'})) :cssText(index(rootdata,{'single','style'})) :addClass(sArgs.class) :cssText(sArgs.style) end function navbox:renderRow(gArgs,lArgs) if not lArgs.content then return end local rootself = self.rootself local rootdata = rootself.data local root = self.root local row = root:tag 'tr':addClass('newstyle_navbox-row') local group if gArgs.content then group = row:tag 'th' :addClass 'newstyle_navbox-group' :wikitext(gArgs.content) :addClass(index(rootdata,{'group','class'})) :cssText(index(rootdata,{'group','style'})) end local list = row:tag 'td':addClass 'newstyle_navbox-list' local subroot if type(lArgs.content)=='table' then list:addClass 'newstyle_navbox-list-with-subgroup' subroot = list:tag 'table' :addClass 'newstyle_navbox' local subObj = zes.new { root=subroot, level=self.level+1, data=lArgs.content, rootself=self } subObj:render() elseif type(lArgs.content)=='string' then list:wikitext(lArgs.content) :addClass(index(rootdata,{'list','class'})) :cssText(index(rootdata,{'list','style'})) end if not group then list:attr('colspan',2) :addClass 'newstyle_navbox-list-without-group' else group:addClass(gArgs.class) :cssText(gArgs.style) end if rootself.isEven and not subroot then list:addClass 'newstyle_navbox-list-even' :addClass(index(rootdata,{'even','class'})) :cssText(index(rootdata,{'even','style'})) elseif not subroot then list:addClass 'newstyle_navbox-list-odd' :addClass(index(rootdata,{'odd','class'})) :cssText(index(rootdata,{'odd','style'})) end if not subroot then rootself.isEven = not isEven end list:addClass(lArgs.class) :cssText(lArgs.style) end function navbox:render() self.root = self.root or hcreate 'table':addClass 'newstyle_navbox hlist' local root = self.root if self.level>0 then root:addClass 'newstyle_navbox-subgroup' end root:addClass('newstyle_navbox-level-'..self.level) local data = self.data root:addClass(index(data,{'body','class'})) :cssText(index(data,{'body','style'})) local navbarEle if data.name then navbarEle = navbar { title=data.name, mini=1 } end self:renderTitle { content = index(data,{'title','content'}), style = index(data,{'title','style'}), class = index(data,{'title','class'}), navbar = navbarEle } local keys = {} for k, v in pairs(data) do if type(k)=='number' then table.insert(keys,k) end end table.sort(keys) for i,k in ipairs(keys) do local v = data[k] if index(v,{'single','content'}) then self:renderSingle(v.single) else self:renderRow((v.group or {}),v.list) end end return root end function zes._navbox(args) return zes.new {args=args}:process():render() end function zes.luaon(frame) local obj = zes.new {args=frame.args} obj:process() return luaon.encode(obj.data) end function zes.direct(frame) return zes._navbox(frame.args) end function zes.navbox(frame) return zes._navbox(frame:getParent().args) end return zes