模块:Navbox:修订间差异

来自Rizline中文维基
无编辑摘要
标签已被回退
无编辑摘要
标签已被回退
第2行: 第2行:
-- This module will implement {{Navbox}}
-- This module will implement {{Navbox}}
--
--
 
local p = {}
local p = {}
 
local navbar = require('Module:Navbar')._navbar
--Context start
local _NavboxContext={}
local NavboxContextNewObj=function(_prefix,_level,_type)
    return {
        prefix = _prefix
        ,level = _level
        ,type = _type
        ,_Context={}
    }
end
 
local NavboxContextMetaFunction={
    __index=function(_obj,key)
      local _key = tostring(key)
      if _key=='prefix' or _key =='level' or _key =='type' then
      return _obj[_key]
  else
        return _obj._Context[_key]
        end
    end
    ,__newindex=function(_obj,key,val)
    local _key = tostring(key)
      if _key=='prefix' or _key =='level' or _key =='type' then
      _obj[_key]=val
  else
        _obj._Context[_key]=val
        end
    end
    ,__tostring=function(_obj)
        local output={}
        table.insert(output,'prefix='.._obj.prefix)
        table.insert(output,'level='.._obj.level)
        table.insert(output,'type='.._obj.type)
        for k,v in pairs(_obj._Context) do
            table.insert(output,k..'='..v)
        end
        return 'context:{\n'..table.concat(output,",\n")..'\n}'
    end
}
 
_NavboxContext.new=function(prefix,level,_type)
    local _prefix = prefix or ""
    local _level = level or 1
 
    local newobj=NavboxContextNewObj(_prefix,_level,_type or '')
    setmetatable(newobj,NavboxContextMetaFunction)
    --[[function newobj:remove(key)
        mw.log(self)
        NavboxContext_Remove(self,key)
    end]]
    return newobj
end
--Context end
 
local navbarFunc = require('Module:Navbar')._navbar
local NavboxContext = _NavboxContext
local getArgs -- lazily initialized
local getArgs -- lazily initialized
local DEBUG=false


--全局性参数锚
local args
local args
local tableRowAdded = false
 
local border
--常量定义 (Constant Define)
local listnums = {}
local Limit={
      vertical=35
    ,horizontal={
        col =20
        ,list=6
      }
    ,vertical_collapsible=20
    ,child=10
}
 
local NavType={
    V="vertical" --垂直,list
    ,H="horizontal" --水平,col
    ,VC="vertical_collapsible" --折叠垂直
}
 
local MainTemplateName = 'Template:NavboxV2'
 
---------------------------------------------------------------
--
--工具箱方法 (Util Function)
--


local function trim(s)
local function trim(s)
第25行: 第103行:
end
end


local function addTableRow(tbl)
---数组除重
     -- If any other rows have already been added, then we add a 2px gutter row.
local function removeDump(arr)
     if tableRowAdded then
    local _t1,_t2={},{}
         tbl
    for _,val in pairs(arr) do
        _t1[val]=true
    end
    --table.remove(arr)
    for key,_ in pairs(_t1) do
        table.insert(_t2,key)
    end
    return _t2
end
 
local function tableToString(_table)
    local outputs={}
    if type(_table)=='table' then
        for k,v in pairs(_table) do
            local output
            if type(v)=='table' then
                output=tableToString(v)
            else
                output=tostring(v)
            end
            table.insert(outputs,tostring(k).."="..output)
        end
    end
    return '{'..table.concat(outputs,",")..'}'
end
 
local debugLog=function(...)
    if DEBUG then
        if #arg==1 then
            mw.log(tostring(arg[1]))
            mw.log("--------------------")
        else
            for k,v in pairs(arg) do
                local pass= false or tostring(k)=='n'
                if not pass then
                    local _v=v
                    if type(v)=='table' then
                        _v=tableToString(v)
                    end
                    mw.log(tostring(_v))
                end
            end
        end
    end
end
 
---------------------------------------------------------------
--
--功能性方法 (Functional Function)
--
 
---获得有效的类型
local getValidType=function(input,defVal)
if NavType.V==input or NavType.H==input or NavType.VC==input then
  return input
end
return defVal
end
 
---检查border判断是不是子Navbox
local borderIsChild=function(border)
if border == 'subgroup' or border == 'child' then
  return true
end
return false
end
 
---获得参数
local getArg=function( _a , _b,defVal,context,_contextKey)
local contextKey = _contextKey or _b
if context and contextKey and context[contextKey] then
  --debugLog('getArg By Context',contextKey)
  return context[contextKey]
else
  local prefix= _a~=nil and _a or ""
  local key= (_b==nil and _a~=nil) and _a or _b
  local argsKey=prefix .. (prefix=="" and "" or "-") ..key
  --debugLog('getArg By InputArg',argsKey)
  return args[ argsKey ] or defVal
end
end
 
---子Navbox参数组判断
local checkHaveChild=function(prefix,valuekey)
    if getValidType(getArg(prefix, valuekey..'-'..'type'),nil) and
      borderIsChild(getArg(prefix, valuekey..'-'..'border')) then
        return true
    end
    return false
end
 
---获得listnum
local function getListnum(prefix,limit,contentEqList)
    debugLog("getListnum",{['prefix']=prefix,['limit']=limit})
    prefix=prefix:gsub('(-)','%%-')
    local listnums={}
    for k, v in pairs(args) do
        k = ('' .. k)
        --debugLog("getListnum,k=",k)
        local listnum =
              ( k:match('^'..prefix..(prefix=="" and "" or "%-")..'list(%d+)$') or
                k:match('^'..prefix..(prefix=="" and "" or "%-")..'list(%d+)%-')
              )or
              ( contentEqList and ( --VerticalCollapsibleTable 的 Content适配
                k:match('^'..prefix..(prefix=="" and "" or "%-")..'content(%d+)$') or
                k:match('^'..prefix..(prefix=="" and "" or "%-")..'content(%d+)%-')
              ) or nil)
        if listnum and tonumber(listnum)<=limit then
            listnum=tonumber(listnum)
            table.insert(listnums,listnum)
            --debugLog("getListnum,listnum=",listnum)
        end
    end
    listnums=removeDump(listnums)
    table.sort(listnums)
    debugLog('list:',listnums)
    debugLog('getListnum End')
    return listnums
end
 
---参数检查和摇匀
function p.shakeArgs(prefix,level)
    local _
    local list_limit=0
 
    _ = getArg(prefix,"title")
    _ = getArg(prefix,"above")
 
     if getArg(prefix,"type")==NavType.H then
      list_limit = Limit.horizontal.list
      for i = 1, Limit.horizontal.col do
          _ = getArg(prefix,"col"..tostring(i).."header")
          if checkHaveChild(prefix,"col"..tostring(i).."header") then
              p.shakeArgs((prefix=="" and "" or "-").."col"..tostring(i).."header",level+1)
          end
 
          _ = getArg(prefix,"col"..tostring(i))
          if checkHaveChild(prefix,"col"..tostring(i)) then
              p.shakeArgs((prefix=="" and "" or "-").."col"..tostring(i),level+1)
          end
 
          _ = getArg(prefix,"col"..tostring(i).."footer")
          if checkHaveChild(prefix,"col"..tostring(i).."footer") then
              p.shakeArgs((prefix=="" and "" or "-").."col"..tostring(i).."footer",level+1)
          end
      end
     end
 
    if getArg(prefix,"type")==NavType.V then
        list_limit = Limit.vertical
    elseif getArg(prefix,"type")==NavType.VC then
        list_limit = Limit.vertical_collapsible
    end
    for i = 1, list_limit do
        _ = getArg(prefix,"group"..tostring(i))
        _ = getArg(prefix,"list"..tostring(i))
 
        if checkHaveChild(prefix,"list"..tostring(i)) then
            --debugLog('shakeArgs',prefix,"list"..tostring(i))
            p.shakeArgs((prefix=="" and "" or "-").."list"..tostring(i),level+1)
        end
        if checkHaveChild(prefix,"content"..tostring(i)) then
            p.shakeArgs((prefix=="" and "" or "-").."content"..tostring(i),level+1)
        end
    end
 
    _ = getArg(prefix,"below")
end
---------------------------------------------------------------
--
--  元素渲染方法 (Element Render)
--
 
---创建表头
local function createNavTableHeader(context)
    debugLog('render TableHeader',context)
    local prefix = context.prefix
    local state ,title ,border =
            getArg(prefix,"state",nil,context)
            ,getArg(prefix,"title")
            ,getArg(prefix,"border",nil,context)
    debugLog('render TableHeader args',{['prefix']=prefix,['state']=state,['title']=title,['border']=border})
 
    local rootTable=
        mw.html.create('table')
            :attr('cellspacing', 0)
            :addClass('nowraplinks')
            :addClass(getArg(prefix,"bodyclass",nil,context))
            :css('border-spacing', 0)
 
    if title and (state ~= 'plain' and state ~= 'off') then
        rootTable
            :addClass('collapsible')
            :addClass( state or 'autocollapse')
    end
 
    if border == 'subgroup' or border == 'child' or border == 'none' then
        rootTable
            :addClass('navbox-subgroup')
            :cssText(getArg(prefix,"bodystyle",nil,context))
            :cssText(getArg(prefix,"style",nil,context))
    else -- regular navobx - bodystyle and style will be applied to the wrapper table
        rootTable
            :addClass('navbox-inner')
            :css('background', 'transparent')
            :css('color', 'inherit')
    end
 
    rootTable:cssText(getArg(prefix,"innerstyle"))
 
    debugLog('render TableHeader End')
    return rootTable
end
 
---分割行 (SplitRow)
local function renderSplitRow(rootTable,context)
    local colspan= context.splitRowcolspan or context.totalColspan
    debugLog('render SplitRow',{
        ['needAddSplitRow']=context.needAddSplitRow,
        ['colspan']=colspan,
    }
    ,context)
    if context.needAddSplitRow then
         rootTable
             :tag('tr')
             :tag('tr')
                 :css('height', '2px')
                 :css('height', '2px')
                 :tag('td')
                 :tag('td')
                :attr('colspan', 3)
                    :attr('colspan',colspan)
    else
     end
     end
      
     context.splitRowcolspan=colspan
     tableRowAdded = true
     context.needAddSplitRow=true
   
    return tbl:tag('tr')
end
end


local function renderNavBar(titleCell)
---创建三键导航
local function renderNavBar(titleCell,context)
    local prefix = context.prefix
    local  navbar , state , border, name , titlestyle =
          getArg(prefix,"navbar",nil,context)
          ,getArg(prefix,"state",nil,context)
          ,getArg(prefix,"border",nil,context)
          ,getArg(prefix,"name")
          ,getArg(prefix,'titlestyle',nil,context)
    debugLog('render Navbar',
        {['prefix']=prefix,
        ['navbar']=navbar,['state']=state,
        ['border']=border,['name']=name,
        ['titlestyle']=titlestyle}
        ,context
    )
     -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
     -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
     -- or right to keep the title centered.
     -- or right to keep the title centered.
     local spacerSide = nil
     local spacerSide = nil


     if args.navbar == 'off' then
     if navbar == 'off' then
         -- No navbar, and client wants no spacer, i.e. wants the title to be shifted to the left. If there's
         -- No navbar, and client wants no spacer, i.e. wants the title to be shifted to the left. If there's
         -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
         -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
         if args.state == 'plain' then spacerSide = 'right' end
         if state == 'plain' then spacerSide = 'right' end
     elseif args.navbar == 'plain' or (not args.name and mw.getCurrentFrame():getParent():getTitle() == 'Template:Navbox' and (border == 'subgroup' or border == 'child' or border == 'none')) then
     elseif navbar == 'plain' or
        (   not name and
            mw.getCurrentFrame():getParent():getTitle() == MainTemplateName and
            (border == 'subgroup' or border == 'child' or border == 'none')
        )
        then
         -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
         -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
        if args.state ~= 'plain' then spacerSide = 'left' end
            if state ~= 'plain' then spacerSide = 'left' end
     else
     else
         -- Will render navbar (or error message). If there's no show/hide link, need a spacer on the right
         -- Will render navbar (or error message). If there's no show/hide link, need a spacer on the right
         -- to balance out the width of the navbar.
         -- to balance out the width of the navbar.
         if args.state == 'plain' then spacerSide = 'right' end
         if state == 'plain' then spacerSide = 'right' end


         titleCell:wikitext(navbar{  
         titleCell:wikitext(navbarFunc{
             args.name,  
             name,
             mini = 1,  
             mini = 1,
             fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') ..  ';background:none transparent;border:none;'
             fontstyle = table.concat(
            {
                  getArg(prefix,'basestyle',nil,context) or ''
                ,(titlestyle or '')
                ,'background:none transparent;border:none'
            }
            ,';')
         })
         })
     end
     end
   
 
     -- Render the spacer div.
     -- Render the spacer div.
     if spacerSide then
     if spacerSide then
第74行: 第400行:
                 :wikitext('&nbsp;')
                 :wikitext('&nbsp;')
     end
     end
    debugLog('render Navbar End')
end
end


--
---标题行
--  Title row
local function renderTitleRow(rootTable,context)
--
    local prefix = context.prefix
local function renderTitleRow(tbl)
    local title = getArg(prefix,"title",nil,context)
     if not args.title then return end
     if not title then return end
    debugLog('render TitleRow',{['prefix']=prefix,['title']=title},context)
     local titleRow = addTableRow(tbl)
    local basestyle = getArg(prefix,"basestyle",nil,context)
   
    renderSplitRow(rootTable,context)
     if args.titlegroup then
     local titleRow=rootTable:tag('tr')
 
    local titlegroup=getArg(prefix,"titlegroup")
     if titlegroup and (not context.notNeedTitlegroup) then
         titleRow
         titleRow
             :tag('th')
             :tag('th')
                 :attr('scope', 'row')
                 :attr('scope', 'row')
                 :addClass('navbox-group')
                 :addClass('navbox-group')
                 :addClass(args.titlegroupclass)
                 :addClass(getArg(prefix,"titlegroupclass"))
                 :cssText(args.basestyle)
                 :cssText(basestyle)
                 :cssText(args.groupstyle)
                 :cssText(getArg(prefix,"groupstyle",nil,context))
                 :cssText(args.titlegroupstyle)
                 :cssText(getArg(prefix,"titlegroupstyle"))
                 :wikitext(args.titlegroup)
                 :wikitext(titlegroup)
     end
     end
   
 
     local titleCell = titleRow:tag('th'):attr('scope', 'col')
     local titleCell = titleRow:tag('th'):attr('scope', 'col')
           
    local titleStyle = getArg(prefix,"titlestyle",nil,context)
     if args.titlegroup then
    local titleColspan = context.totalColspan
     if titlegroup and (not context.notNeedTitlegroup) then
         titleCell
         titleCell
             :css('border-left', '2px solid #fdfdfd')
             :css('border-left', '2px solid #fdfdfd')
             :css('width', '100%')
             :css('width', '100%')
        titleColspan = titleColspan - 1
     end
     end
   
    local titleColspan = 2
    if args.imageleft then titleColspan = titleColspan + 1 end
    if args.image then titleColspan = titleColspan + 1 end
    if args.titlegroup then titleColspan = titleColspan - 1 end
   
     titleCell
     titleCell
         :cssText(args.basestyle)
         :cssText(basestyle)
         :cssText(args.titlestyle)
         :cssText(titleStyle)
         :addClass('navbox-title')
         :addClass('navbox-title')
         :addClass(args.titleclass)
         :addClass(getArg(prefix,"titleclass",nil,context))
         :attr('colspan', titleColspan)
         :attr('colspan', titleColspan)
 
     renderNavBar(titleCell)
     renderNavBar(titleCell,context)


     titleCell
     titleCell
         :tag('div')
         :tag('div')
             :css('font-size', '110%')
             :css('font-size', '110%')
             :wikitext(addNewline(args.title))
             :wikitext(addNewline(title))
end
 
--
--  Above/Below rows
--


local function getAboveBelowColspan()
    debugLog('render TitleRow End')
    local ret = 2
    if args.imageleft then ret = ret + 1 end
    if args.image then ret = ret + 1 end
    return ret
end
end


local function renderAboveRow(tbl)
---上列
     if not args.above then return end
local function renderAboveRow(rootTable,context)
    local prefix = context.prefix
    local above = getArg(prefix,"above")
     if not above then return end
    debugLog('render AboveRow',{['prefix']=prefix},context)
    renderSplitRow(rootTable,context)


     addTableRow(tbl)
     local Colspan=context.totalColspan
    local AboveRow=rootTable:tag('tr')
    AboveRow
         :tag('td')
         :tag('td')
             :addClass('navbox-abovebelow')
             :addClass('navbox-abovebelow')
             :addClass(args.aboveclass)
             :addClass(getArg(prefix,"aboveclass"))
             :cssText(args.basestyle)
             :cssText(getArg(prefix,"basestyle"))
             :cssText(args.abovestyle)
             :cssText(getArg(prefix,"abovestyle"))
             :attr('colspan', getAboveBelowColspan())
             :attr('colspan', Colspan)
             :tag('div')
             :tag('div')
                 :wikitext(addNewline(args.above))
                 :wikitext(addNewline(above))
 
    debugLog('render AboveRow End')
end
end


local function renderBelowRow(tbl)
---下列
     if not args.below then return end
local function renderBelowRow(rootTable,context)
    local prefix = context.prefix
    local below = getArg(prefix,"below")
     if not below then return end
    debugLog('render BelowRow',{['prefix']=prefix},context)
    renderSplitRow(rootTable,context)


     addTableRow(tbl)
     local Colspan=context.totalColspan
    local BelowRow=rootTable:tag('tr')
    BelowRow
         :tag('td')
         :tag('td')
             :addClass('navbox-abovebelow')
             :addClass('navbox-abovebelow')
             :addClass(args.belowclass)
             :addClass(getArg(prefix,"belowclass"))
             :cssText(args.basestyle)
             :cssText(getArg(prefix,"basestyle"))
             :cssText(args.belowstyle)
             :cssText(getArg(prefix,"belowstyle"))
             :attr('colspan', getAboveBelowColspan())
             :attr('colspan', Colspan)
             :tag('div')
             :tag('div')
                 :wikitext(addNewline(args.below))
                 :wikitext(addNewline(below))
 
    debugLog('render BelowRow End')
end
 
---------------------------------------------------------------
 
--数据列的方法生成器
local function _renderColRow_FunctionBuilder(rootTable,context,nodeFunc)
    debugLog("_renderColRow_FunctionBuilder builded",{['context']=context})
    return function(listCellDivToWrite,divNotClose)
        debugLog(debug.traceback('FunctionInrenderColRow'),{['context']=context,['divNotClose']=divNotClose})
        if not divNotClose then
          listCellDivToWrite:done()--div end
          :node(
              rootTable and nodeFunc(rootTable,context) or
              nodeFunc(context)
          )
          :tag('div'):done()
        else
          listCellDivToWrite:node(nodeFunc(rootTable,context))
        end
    end
end
 
---数据行,统一的实现
local function _renderListRow(rootTable,context,OtherListFunction)
    renderSplitRow(rootTable,context)
 
    local prefix, level = context.prefix, context.level
    local listnum = context.listnum or 1
    local isFirst, isOdd = (listnum==1) ,(listnum % 2) == 1
    local ImageRowspan = 2 * context.totalRowspan - 1 + ( context['imageCellCompensate'] or 0)
    local notNeedImage, notNeedGroup =
            context.notNeedImage
            ,context.notNeedGroup
    debugLog('ValueRow Implement',
            {['prefix']=prefix,
            ['listnum']=listnum,
            ['ImageRowspan']=ImageRowspan,
            ['HaveOtherListFunction']=tostring(not not OtherListFunction),
            ['notNeedImage']=notNeedImage,
            ['notNeedGroup']=notNeedGroup},
            context)
    local listRow=rootTable:tag('tr')
    local groupCell,listCell
    local insertImage=false
 
    --image
    local  imageLeft , image , insertImage =
                getArg(prefix,"imageleft",nil,context)
                ,getArg(prefix,"image",nil,context)
                ,false
    --CollapsibleListRow 适配
    if context.notImageLeftCell then
        imageLeft = nil
    end
    if context.notImageCell then
        image = nil
    end
    if isFirst and (not notNeedImage) then
        if imageLeft then
            debugLog('imageLeftRow',{['imageLeft']=imageLeft})
            listRow:tag('td')--[[,{['parent']=listRow}]]
            :addClass('navbox-image')
            :addClass(getArg(prefix,"imageclass",nil,context))
            :css('width', '0%')
            :css('padding', '0px 2px 0px 0px')
            :cssText(getArg(prefix,"imageleftstyle",nil,context))
            :attr('rowspan', ImageRowspan)
            :tag('div')
                :wikitext(addNewline(imageLeft))
            :done() --div done
            :done() --td done
        end
        if image then
          insertImage=true
        end
    end
 
    --list pre
    local listHaveChild = checkHaveChild(prefix,'list'..listnum)
    local contentHaveChild = context.contentEqList and checkHaveChild(prefix,'content'..listnum)
 
    --group
    local  group, groupwidth , grouppadding , removeGroupPadding =
            getArg(prefix,"group"..listnum,nil,context)
            ,( ( group and getArg(prefix,"groupwidth") ) or nil )
            ,( getArg(prefix,"grouppadding") or '0em 0.75em;' )
            ,( getArg(prefix,'removeGroupPadding',false) and level > 1 )
    if group and not notNeedGroup then
        debugLog('groupTh',{['group']=group})
        groupCell=listRow:tag('th')
            :attr('scope', 'row')
            :addClass('navbox-group')
            :addClass(getArg(prefix,"groupclass",nil,context))
            :cssText(getArg(prefix,"basestyle"))
            :css((( groupwidth and {['width']=groupwidth}) or {}))
            :cssText(getArg(prefix,"groupstyle"))
            :cssText(getArg(prefix,'group' .. listnum .. 'style'))
        local tempEle=groupCell
        if (borderIsChild(getArg(prefix,"border"))) and (getArg(prefix,'type')==NavType.V) and (not removeGroupPadding) then --针对列式子组合的适配
        groupCell:cssText("padding-left:0em;padding-right:0em;")
 
        tempEle=tempEle:tag("div"):css("padding",grouppadding)
        end
        tempEle:wikitext(group)
 
    end
 
    --list
    do
        listCell=listRow:tag('td')
        if group and not notNeedGroup then
            listCell
                :css('text-align', 'left')
                :css('border-left-width', '2px')
                :css('border-left-style', 'solid')
        else
            listCell:attr('colspan', 2)
        end
 
        if not groupwidth then
            listCell:css('width', '100%')
        end
 
        local evenOdd = getArg(prefix,"evenodd")
        evenOdd = (
            evenOdd == 'swap' and
            (isOdd and 'even' or 'odd') or
            (isOdd and (evenOdd or 'odd') or (evenOdd or 'even'))
        )
        local evenOddStyle=(isOdd and getArg(prefix,"evenstyle")) or getArg(prefix,"oddstyle")
        if context.lockEvenOdd then --CollapsibleListRow 适配
            evenOdd='odd'
        end
        if context.noEvenOddStyle then --CollapsibleListRow 适配
        evenOddStyle=''
        end
 
        local list1padding = (notNeedGroup) and getArg(prefix,"list1padding",nil,context) or
                            '0em 0.25em'
        local listNpadding = (isFirst and list1padding) or
                            ( getArg(prefix,"listpadding",nil,context) or '0em 0.25em' )
        local listNstyle= --((not notNeedGroup))
                        (isFirst and getArg(prefix,'list1style','',context) ) or
                        getArg(prefix,'list'..listnum .. 'style','')
        local liststyle = getArg(prefix,"liststyle",'',context)
 
  listCell
            :css('padding', '0px')
            :cssText(liststyle)
            :cssText(evenOddStyle)
            :cssText(listNstyle)
            :addClass('navbox-list')
            :addClass('navbox-' .. evenOdd)
            :addClass(getArg(prefix,"listclass"))
        local tempdiv=listCell:tag('div'):css('padding', listNpadding)
        --local listHaveChild = checkHaveChild(prefix,'list'..listnum)
        --local contentHaveChild = context.contentEqList and checkHaveChild(prefix,'content'..listnum)
        if OtherListFunction then
            debugLog('ValueRow OtherListFunction',{['otherListFunctionDivNotClose']=context.otherListFunctionDivNotClose})
            --OtherListFunction(listCell)
            OtherListFunction(tempdiv,context.otherListFunctionDivNotClose)
        elseif (listHaveChild or contentHaveChild) and level<= Limit.child then
            local listKeyName='list'
            if contentHaveChild then
                listKeyName='content'
            end
            local childContext=NavboxContext.new(
                prefix..(prefix=='' and '' or '-')..listKeyName..listnum ,
                level+1 ,
                getValidType(
                    getArg(prefix..(prefix=='' and '' or '-')..
                                  listKeyName..listnum,'type'),
                    NavType.V
                )
            )
            debugLog('ValueRow NewChild',childContext)
            tempdiv:done()-- div end
                :node(p.renderNavTable(childContext))
                :tag('div'):done()
        else
            local listContent = getArg(prefix,'list'..listnum,'')..
                          ( ((not context.contentEqList ) and '') or getArg(prefix,'content' .. listnum,''))
            debugLog('ValueRow listnum',{['listnum']=listnum})
            tempdiv:wikitext(addNewline(listContent))
        end
    end
    --end
 
    if insertImage then
      debugLog('imageRow',{['image']=image})
      listRow:tag('td')
          :addClass('navbox-image')
          :addClass(getArg(prefix,"imageclass",nil,context))
          :css('width', '0%')
          :css('padding', '0px 0px 0px 2px')
          :cssText(getArg(prefix,"imagestyle",nil,context))
          :attr('rowspan', ImageRowspan)
          :tag('div')
              :wikitext(addNewline(image))
    end
    debugLog('ValueRow Implement End')
end
 
---数据行,垂直式的具体实现
local function renderListRow(rootTable,context)
    debugLog('render ListRow',context)
    _renderListRow(rootTable,context)
    debugLog('render ListRow End')
end
end
 
--
---------------------------------------------------------------
--   List rows
 
--
---数据列,水平式的具体实现 (ColRow)
local function renderListRow(tbl, listnum)
local function _renderColRow(rootTable,context)
     local row = addTableRow(tbl)
     local prefix, level = context.prefix, context.level
      
    local fullwidth  =getArg(prefix,"fullwidth")
     if listnum == 1 and args.imageleft then
     local col1header,col1,col1footer=
         row
          getArg(prefix,'col'..'1'..'header')
             :tag('td')
          ,getArg(prefix,'col'..'1')
                 :addClass('navbox-image')
          ,getArg(prefix,'col'..'1'..'footer')
                 :addClass(args.imageclass)
     debugLog('ColRow Implement',{['prefix']=prefix},context)
                 :css('width', '0%')
    --new table root
                 :css('padding', '0px 2px 0px 0px')
    rootTable=mw.html.create('table')
                :cssText(args.imageleftstyle)
    rootTable
                :attr('rowspan', 2 * #listnums - 1)
        :addClass("navbox-columns-table")
                :tag('div')
        :attr("cellspacing","0")
                     :wikitext(addNewline(args.imageleft))
        :cssText("text-align:left;")
        :cssText( ( col1header or fullwidth ) and
            "width:100%;" or
            "width:auto;margin-left:auto;margin-right:auto;"
        )
        :cssText(getArg(prefix,"coltablestyle"))
 
    local headerTR,colbodyTR,footerTR=nil,nil,nil
 
    context.needAddSplitRow=false
    context.splitRowcolspan=1
    --header
    if col1header then
         renderSplitRow(rootTable,context)
        debugLog('ColRow Header',{})
        headerTR=rootTable:tag('tr')
        for colnum=1,Limit.horizontal.col do
            debugLog('ColRow Header',colnum)
            local isFirst,isOdd = colnum == 1, (colnum % 2) == 1
             local colheaderkey='col'..colnum..'header'
            local colNheader= isFirst and col1header or getArg(prefix,colheaderkey)
 
            if  headerTR  and colNheader then
                debugLog('ColRow Herder Cell',{['colnum']=colnum})
                local headerNCell=headerTR:tag('td')
                 headerNCell
                    :addClass('navbox-abovebelow')
                    :cssText(isFirst and "" or "border-left:2px solid #fdfdfd;")
                    :cssText(getArg(prefix, "colheaderstyle"))
                    :cssText(getArg(prefix, colheaderkey..'style'))
                    :attr(( colnum~=Limit.horizontal.col and {['colspan']=getArg(prefix,colheaderkey..'colspan',1)} ) or {})
--[[                if checkHaveChild(prefix,colheaderkey) and level<= Limit.child then
                    local childContext=NavboxContext.new(colheaderkey ,level+1 ,NavType.H)
                    debugLog('ColRow Herder NewChild',childContext)
                    headerNCell:node(p.renderNavTable(childContext):allDone())
                 else]]
                    --debugLog('ColRow Herder Cell',{['colnum']=colnum})
                    --headerNCell
                    :wikitext(addNewline("'''"..colNheader.."'''"))
                 --end
            end
        end
        debugLog('ColRow Header End',{['colnum']=colnum})
    end
 
    --col
    local col1havechild = checkHaveChild(prefix,"col1")
    if col1 or col1havechild then
        renderSplitRow(rootTable,context)
        debugLog('ColRow Body',{
        ['col1havechild']=col1havechild
        })
        colbodyTR=rootTable:tag('tr'):cssText('vertical-align:top;')
        if not(col1header or col1footer or fullwidth) then
            local padding,test0=getArg(prefix, "padding"),nil
            if padding then
                padding = trim(padding)
                test0=padding:find('^0[%%%a]?[%a]?[;]?$')
            end
            if test0~=nil or padding=='off' then else
                 colbodyTR
                    :tag('td')
                        :css("width", padding or '5em')
                        :wikitext('&nbsp;&nbsp;&nbsp;')
                    :done()
            end
        end
        for colnum=1,Limit.horizontal.col do
            debugLog('ColRow Body',colnum)
            local isFirst,isOdd = colnum == 1, (colnum % 2) == 1
            local colkey = 'col'..colnum
            local colN = isFirst and col1 or getArg(prefix,colkey)
            local colNhavechild = isFirst and col1havechild or
                                  checkHaveChild(prefix,colkey)
            if  colN or colNhavechild then
                local oddevenstyle = getArg( prefix , isOdd and 'oddcolstyle' or 'evencolstyle')
                local colNCell=colbodyTR
                    :tag('td')
                    :css("padding","0px")
                    :cssText(((not isFirst) and "border-left:2px solid #fdfdfd;" ) or '')
                    :cssText(getArg(prefix,'colstyle'))
                    :cssText(oddevenstyle)
                    :cssText(getArg(prefix, colkey..'style'))
                    :css('width', ( getArg(prefix, colkey..'width') or getArg(prefix,'colwidth') ) or '10em')
 
                if checkHaveChild(prefix,colkey) and level<= Limit.child then
                    local childContext=NavboxContext.new(prefix..(prefix=='' and '' or '-')..colkey ,level+1 ,getValidType(getArg(prefix,'type'),NavType.H))
                    debugLog('ColRow Body NewChild',childContext)
                    colNCell:tag('div'):done()
                    :node(p.renderNavTable(childContext):allDone())
                    :tag('div'):done()
                else
                    debugLog('ColRow Body Cell',{['colnum']=colnum})
                     colNCell:tag('div'):wikitext(addNewline(colN))
                end
            end
            debugLog('ColRow Body End',{['colnum']=colnum})
        end
     end
     end
 
     if args['group' .. listnum] then
    --footer
         local groupCell = row:tag('th')
     if col1footer then
          
        renderSplitRow(rootTable,context)
        groupCell
        debugLog('ColRow footer',{})
              :attr('scope', 'row')
         footerTR=rootTable:tag('tr')
              :addClass('navbox-group')
         for colnum=1,Limit.horizontal.col do
              :addClass(args.groupclass)
            debugLog('ColRow footer',colnum)
              :cssText(args.basestyle)
            local isFirst,isOdd = colnum == 1, (colnum % 2) == 1
                
            local colfooterkey='col'..colnum..'footer'
        if args.groupwidth then
            local colNfooter=isFirst and col1footer or getArg(prefix,colfooterkey)
            groupCell:css('width', args.groupwidth)
 
            if colNfooter then
                debugLog('ColRow footer Cell',{['colnum']=colnum})
                local footerNCell=footerTR:tag('td')
                footerNCell
                    :addClass('navbox-abovebelow')
                    :cssText(isFirst and "" or "border-left:2px solid #fdfdfd;")
                    :cssText(getArg(prefix, "colfooterstyle"))
                    :cssText(getArg(prefix, colfooterkey..'style'))
                    :attr(( colnum~=Limit.horizontal.col and {['colspan']=getArg(prefix,colfooterkey..'colspan',1)}) or {})
--[[               if checkHaveChild(prefix,colfooterkey) and level<= Limit.child then
                    local childContext=NavboxContext.new(colfooterkey ,level+1 ,NavType.H)
                    debugLog('ColRow footer NewChild',childContext)
                    footerNCell:node(p.renderNavTable(childContext):allDone())
                else]]
                    --debugLog('ColRow footer Cell',{['colnum']=colnum})
                    --footerNCell
                    :wikitext(addNewline("'''"..colNfooter.."'''"))
                --end
            end
         end
         end
         
         debugLog('ColRow footer End',{['colnum']=colnum})
         groupCell
            :cssText(args.groupstyle)
            :cssText(args['group' .. listnum .. 'style'])
            :wikitext(args['group' .. listnum])
     end
     end
    debugLog('ColRow Implement End')
    return rootTable:allDone()
end
--数据列,具体实现
local function renderColRow(rootTable,context)
    debugLog('renderColRow',{['context']=context})
    context.notNeedGroup = true
    context['list1padding']='0px'
    context['list1style']="background:transparent;color:inherit;"
    context['otherListFunctionDivNotClose']=true
    context['imageCellCompensate']=2
    _renderListRow(
        rootTable,context,
        _renderColRow_FunctionBuilder(rootTable,context,_renderColRow)
    )
      
      
     local listCell = row:tag('td')
     --clean up
    context.notNeedGroup=nil
    context['list1padding']=nil
    context['list1style']=nil
    context['otherListFunctionDivNotClose']=nil
    context['imageCellCompensate']=nil
    debugLog('renderColRow End')
end
 
---------------------------------------------------------------


     if args['group' .. listnum] then
--折叠行式的子Nabox
        listCell
local function _renderSmallNavboxInCollapsibleListRow(rootTable,context)
            :css('text-align', 'left')
     local prefix, level = context.prefix, context.level
            :css('border-left-width', '2px')
    debugLog('_renderSmallNavboxInCollapsibleListRow',{['prefix']=prefix},{['context']=context})
            :css('border-left-style', 'solid')
    local listnum = context.listnum
 
    --部分需要压制传入的样式
    context.bodyclass = ''
    context.titleclass = ''
    context.groupclass = ''
    context.imageclass = ''
    context.bodystyle = ''
    context.style = ''
    context.basestyle = ''
    context.imagestyle = ''
    context.imageleftstyle = ''
 
    --传入renderNavBar,renderTitleRow
    context.navbar='plain'
    context.border='child'
    local selected , abbrN , state =
          getArg(prefix,'selected') , getArg(prefix,'abbr'..listnum) , 'uncollapsed'
    if selected ~= nil and selected == abbrN then
      state='uncollapsed'
     else
     else
        listCell:attr('colspan', 2)
      state=getArg(prefix,'state'..listnum,'collapsed')
     end
     end
      
     context.state = state
     if not args.groupwidth then
 
        listCell:css('width', '100%')
     --传入renderTitleRow
    --context.titleEqGroup=true
    context.notNeedTitlegroup=true
    context.titlestyle=table.concat(
    {
          (getArg(prefix,'basestyle','')                  )
        ,(getArg(prefix,'groupstyle','')                )
        ,(getArg(prefix,'secttitlestyle','')            )
        ,(getArg(prefix,'group'..listnum..'style','')    )
        ,(getArg(prefix,'sect'..listnum..'titlestyle',''))
    }
    ,';')
    context.title=(getArg(prefix,'group'..listnum,'')  )..
                  (getArg(prefix,'sect'..listnum,'')  )..
                  (getArg(prefix,'section'..listnum,''))
 
    --传入renderListRow
    context.contentEqList=true
    context.notNeedGroup=true
    context.liststyle=table.concat(
    {
          (getArg(prefix,'liststyle','')                )
        ,(getArg(prefix,'contentstyle','')            )
        ,(getArg(prefix,'list'..listnum..'style','')  )
        ,(getArg(prefix,'content'..listnum..'style',''))
    }
    ,';')
    local totalColspan=2 --title,above,below
    local totalRowspan=1 --image,imageleft
    --传入image
    local  imageLeft,image=
                getArg(prefix,"imageleft"..listnum,nil,context,'imageleft')
                ,getArg(prefix,"image"..listnum,nil,context,'image')
    if imageLeft then
    totalColspan = totalColspan + 1
    context.imageleft = imageLeft
    else
    context.notImageLeftCell=true --CollapsibleListRow 适配
     end
     end
      
     if image then
    local isOdd = (listnum % 2) == 1
    totalColspan = totalColspan + 1
    local rowstyle = args.evenstyle
    context.image = image
    if isOdd then rowstyle = args.oddstyle end
    local evenOdd
    if args.evenodd == 'swap' then
        if isOdd then evenOdd = 'even' else evenOdd = 'odd' end
     else
     else
        if isOdd then evenOdd = args.evenodd or 'odd' else evenOdd = args.evenodd or 'even' end
    context.notImageCell=true --CollapsibleListRow 适配
     end
     end


     listCell
     context.totalColspan = totalColspan
        :css('padding', '0px')
    context.totalRowspan = totalRowspan
        :cssText(args.liststyle)
    context.splitRowcolspan = totalColspan
        :cssText(rowstyle)
    context.lockEvenOdd=true --CollapsibleListRow 适配
        :cssText(args['list' .. listnum .. 'style'])
        :addClass('navbox-list')
        :addClass('navbox-' .. evenOdd)
        :addClass(args.listclass)
        :tag('div')
            :css('padding', (listnum == 1 and args.list1padding) or args.listpadding or '0em 0.25em')
            :wikitext(addNewline(args['list' .. listnum]))


     if listnum == 1 and args.image then
     debugLog('SmallNavboxInCollapsibleListRow Implement','listnum='..listnum,context)
        row
    --start
            :tag('td')
    local rootTable2 = createNavTableHeader(context)
                :addClass('navbox-image')
    renderTitleRow(rootTable2,context)
                :addClass(args.imageclass)
    --only 1 list
                :css('width', '0%')
    local otherListFunction
                :css('padding', '0px 0px 0px 2px')
    local listHaveChild = checkHaveChild(prefix,'list'..listnum)
                :cssText(args.imagestyle)
    local contentHaveChild = context.contentEqList and checkHaveChild(prefix,'content'..listnum)
                :attr('rowspan', 2 * #listnums - 1)
    if (listHaveChild or contentHaveChild) and level<= Limit.child then
                :tag('div')
        local listKeyName='list'
                    :wikitext(addNewline(args.image))
        if contentHaveChild then
            listKeyName='content'
        end
        local childContext=NavboxContext.new(
                              prefix..(prefix=='' and '' or '-')..listKeyName..listnum ,
                              level+1 ,
                              getValidType(getArg(prefix..(prefix=='' and '' or '-')..listKeyName..listnum,'type'),NavType.V))
        debugLog('SmallNavboxInCollapsibleListRow NewChild',childContext)
        otherListFunction=_renderColRow_FunctionBuilder(nil,childContext,p.renderNavTable)
     end
     end
    context.noEvenOddStyle=true
    _renderListRow(rootTable2,context,otherListFunction)
    context.noEvenOddStyle=nil
    debugLog('_renderSmallNavboxInCollapsibleListRow End')
    return rootTable2:allDone()
end
end


---折叠行具体实现
local function renderCollapsibleListRow(rootTable,context)
  local prefix, level = context.prefix, context.level
  debugLog('renderCollapsibleListRow',{['prefix']=prefix},{['context']=context})
  context.notNeedGroup = true
  local listnum = context.listnum
  local context_function
  if getArg(prefix,'group'..listnum)  or
      getArg(prefix,'sect'..listnum)    or
      getArg(prefix,'section'..listnum) then
        local grandChild_context=NavboxContext.new(prefix,level)
        grandChild_context.notNeedGroup=true
        grandChild_context.listpadding=getArg(prefix,'listpadding')
        grandChild_context.listnum=listnum
        context_function=_renderColRow_FunctionBuilder(
            rootTable,grandChild_context,
            _renderSmallNavboxInCollapsibleListRow
        )
        debugLog('renderCollapsibleListRow function generate',{['context']=context,['grandChild_context']=grandChild_context})
    end
    context.noEvenOddStyle=true
    debugLog('renderCollapsibleListRow renderListRow',{['context']=context})
    _renderListRow(rootTable,context,context_function)
    context.noEvenOddStyle=nil
    debugLog('renderCollapsibleListRow End')
end


---------------------------------------------------------------
--
--
--  Tracking categories
--  Tracking categories
--
--
local function needsHorizontalLists(context)
    local prefix = context.prefix
    local border ,listclass ,bodyclass =
            context.border    or getArg(prefix,'border')
            ,context.listclass or getArg(prefix,'listclass')
            ,context.bodyclass or getArg(prefix,'bodyclass')
    if borderIsChild(border)
        or getArg(prefix,'tracking') == 'no' then
        return false
    end


local function needsHorizontalLists()
     local listClasses = {'plainlist', 'hlist', 'hlist hnum', 'hlist hwrap', 'hlist vcard', 'vcard hlist', 'hlist vevent', 'hlist hlist-pipe'}
    if border == 'child' or border == 'subgroup'  or args.tracking == 'no' then return false end
   
     local listClasses = {'plainlist', 'hlist', 'hlist hnum', 'hlist hwrap', 'hlist vcard', 'vcard hlist', 'hlist vevent', 'hlist hlist-pipe', 'hlist hlist-hyphen'}
     for i, cls in ipairs(listClasses) do
     for i, cls in ipairs(listClasses) do
         if args.listclass == cls or args.bodyclass == cls then
         if listclass == cls or bodyclass == cls then
             return false
             return false
         end
         end
第271行: 第1,048行:
end
end


local function hasBackgroundColors()
local function hasBackgroundColors(context)
     return mw.ustring.match(args.titlestyle or '','background') or mw.ustring.match(args.groupstyle or '','background') or mw.ustring.match(args.basestyle or '','background')
    local prefix = context.prefix
    local titlestyle ,groupstyle ,basestyle =
            context.titlestyle or getArg(prefix,'titlestyle')
            ,context.groupstyle or getArg(prefix,'groupstyle')
            ,context.basestyle  or getArg(prefix,'basestyle')
     return mw.ustring.match(titlestyle or '','background') or
          mw.ustring.match(groupstyle or '','background') or
          mw.ustring.match(basestyle or '','background')
end
end


local function argNameAndRealTitleAreDifferent()
local function argNameAndRealTitleAreDifferent(context)
if border == 'child' or border == 'subgroup' or args.tracking == 'no' then return false end
    local prefix = context.prefix
    local border ,name =
            getArg(prefix,'border',nil,context)
            ,getArg(prefix,'name',nil,context)
    if borderIsChild(border)
        or getArg(prefix,'tracking') == 'no' then
        return false
    end


if args.name ~= mw.title.getCurrentTitle().text then
    if name ~= mw.title.getCurrentTitle().text then
return true
        return true
end
    end
return false
    return false
end
end


local function getTrackingCategories()
local function getTrackingCategories(context)
     local cats = {}
     local cats = {}
     if needsHorizontalLists() then table.insert(cats, '没有使用水平列表的导航模板') end
     if needsHorizontalLists(context) then table.insert(cats, '没有使用水平列表的导航框') end
     if hasBackgroundColors() then table.insert(cats, '使用背景颜色的导航模板') end
     if hasBackgroundColors(context) then table.insert(cats, '使用背景颜色的导航框') end
     if argNameAndRealTitleAreDifferent() then table.insert(cats, 'name和实际不同的导航模板') end
     if argNameAndRealTitleAreDifferent(context) then table.insert(cats, 'name參數和實際不同的導航框') end
     return cats
     return cats
end
end


local function renderTrackingCategories(builder)
local function renderTrackingCategories(builder,context)
     local title = mw.title.getCurrentTitle()
     local title = mw.title.getCurrentTitle()
     if title.namespace ~= 10 then return end -- not in template space
     if title.namespace ~= 10 then return end -- not in template space
     local subpage = title.subpageText
     local subpage = title.subpageText
     if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end
     if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end
   
 
     for i, cat in ipairs(getTrackingCategories()) do
     for i, cat in ipairs(getTrackingCategories(context)) do
         builder:wikitext('[[Category:' .. cat .. ']]')  
         builder:wikitext('[[Category:' .. cat .. ']]')
     end
     end
end
end


---------------------------------------------------------------
--
--
--   Main navbox tables
-- SubType Implement
--
--
local function renderMainTable()
 
     local tbl = mw.html.create('table')
---水平式
        :attr('cellspacing', 0)
local function renderHorizontalTable(context)
        :addClass('nowraplinks')
    debugLog('render Horizontal NavTable',context)
        :addClass(args.bodyclass)
     local prefix, level = context.prefix, context.level
           
 
     if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
    local rootTable = createNavTableHeader(context)
        tbl
 
            :addClass('collapsible')
    local listnums=getListnum(prefix,Limit.horizontal.list)
            :addClass(args.state or 'autocollapse')
 
    local totalColspan=2 --title,above,below
    local totalRowspan=#listnums --image,imageleft
    if getArg(prefix,"imageleft",nil,context) then totalColspan =totalColspan + 1 end
    if getArg(prefix,"image",nil,context) then totalColspan =totalColspan + 1 end
    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    --context.splitRowcolspan = totalColspan
 
    renderTitleRow(rootTable,context)
    renderAboveRow(rootTable,context)
 
     if listnums==nil or #listnums==0 then --没有list的话,只有col
    debugLog('render Horizontal NavTable,no list',{listnums})
    context.listnum=1
    renderColRow(rootTable,context)
    --context.notNeedImage=true
    context.splitRowcolspan = totalColspan
    else
    debugLog('render Horizontal NavTable,have list with col',{listnums})
    for i,listnum in ipairs(listnums) do
        context.listnum=listnum
        if listnum==1 then
          --一行Col
          renderColRow(rootTable,context)
          context.notNeedImage=true
          context.splitRowcolspan = totalColspan
        else
          context.notNeedImage=nil
        end
        _renderListRow(rootTable,context)
    end
     end
     end
    renderBelowRow(rootTable,context)
     tbl:css('border-spacing', 0)
 
     if border == 'subgroup' or border == 'child' or border == 'none' then
     renderTrackingCategories(rootTable,context)
        tbl
     debugLog('render Horizontal NavTable End')
            :addClass('navbox-subgroup')
    return rootTable
            :cssText(args.bodystyle)
end
            :cssText(args.style)
 
     else -- regular navobx - bodystyle and style will be applied to the wrapper table
---垂直式
        tbl
local function renderVerticalTable(context)
            :addClass('navbox-inner')
    debugLog('render Vertical NavTable',context)
            :css('background', 'transparent')
    local prefix, level = context.prefix, context.level
            :css('color', 'inherit')
 
    local rootTable = createNavTableHeader(context)
 
    local listnums=getListnum(prefix,Limit.vertical)
 
     local totalColspan=2 --title,above,below
    local totalRowspan=#listnums --image,imageleft
    if getArg(prefix,"imageleft",nil,context) then totalColspan =totalColspan + 1 end
    if getArg(prefix,"image",nil,context) then totalColspan =totalColspan + 1 end
    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    --context.splitRowcolspan = totalColspan
 
    renderTitleRow(rootTable,context)
    renderAboveRow(rootTable,context)
    for i,listnum in ipairs(listnums) do
        context.listnum=listnum
        renderListRow(rootTable,context)
     end
     end
     tbl:cssText(args.innerstyle)
     renderBelowRow(rootTable,context)
 
    renderTitleRow(tbl)
     renderTrackingCategories(rootTable,context)
     renderAboveRow(tbl)
     debugLog('render Vertical NavTable End')
    for i, listnum in ipairs(listnums) do
     return rootTable
        renderListRow(tbl, listnum)  
     end
    renderBelowRow(tbl)
   
     return tbl
end
end


function p._navbox(navboxArgs)
---垂直折叠式
     args = navboxArgs
local function renderVerticalCollapsibleTable(context)
   
     debugLog('render VerticalCollapsible NavTable',context)
     for k, v in pairs(args) do
    local prefix, level = context.prefix, context.level
        local listnum = ('' .. k):match('^list(%d+)$')
 
        if listnum then table.insert(listnums, tonumber(listnum)) end
     local rootTable = createNavTableHeader(context)
 
    local listnums=getListnum(prefix,Limit.vertical
      ,(--[[context.contentEqList or ]]true) --VerticalCollapsibleTable 的 Content适配
    )
 
    local totalColspan=2 --title,above,below
    local totalRowspan=#listnums --image,imageleft
    if getArg(prefix,"imageleft",nil,context) then totalColspan =totalColspan + 1 end
    if getArg(prefix,"image",nil,context) then totalColspan =totalColspan + 1 end
    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    --context.splitRowcolspan = totalColspan
 
    renderTitleRow(rootTable,context)
    renderAboveRow(rootTable,context)
    for i,listnum in ipairs(listnums) do
        context.listnum=listnum
        renderCollapsibleListRow(rootTable,context)
     end
     end
     table.sort(listnums)
     renderBelowRow(rootTable,context)
    border = trim(args.border or args[1] or '')


     -- render the main body of the navbox
     renderTrackingCategories(rootTable,context)
     local tbl = renderMainTable()
     debugLog('render VerticalCollapsible NavTable End')
    return rootTable
end


    -- render the appropriate wrapper around the navbox, depending on the border param
---Type Selector
     local res = mw.html.create()
function p.renderNavTable(context)
     if border == 'none' then
    local navtype  = context.type
         res:node(tbl)
    debugLog('render NavTable')
     elseif border == 'subgroup' or border == 'child' then
     debugLog('Type='..navtype)
         -- We assume that this navbox is being rendered in a list cell of a parent navbox, and is
    local result
        -- therefore inside a div with padding:0em 0.25em. We start with a </div> to avoid the
     if navtype==NavType.H then
        -- padding being applied, and at the end add a <div> to balance out the parent's </div>
         result=renderHorizontalTable(context)
        res
     elseif navtype==NavType.VC then
            :wikitext('</div>') -- mw.html 未支持 unclosed
         result=renderVerticalCollapsibleTable(context)
            :node(tbl)
            :wikitext('<div>') -- mw.html 未支持 unclosed
     else
     else
         res
         result=renderVerticalTable(context)
            :tag('table')
                :attr('cellspacing', 0)
                :addClass('navbox')
                :css('border-spacing', 0)
                :cssText(args.bodystyle)
                :cssText(args.style)
                :tag('tr')
                    :tag('td')
                        :css('padding', '2px')
                        :node(tbl)
     end
     end
    debugLog('render NavTable End')
     renderTrackingCategories(res)
     return result
end
     return tostring(res)
 
--Main Funtion
function p._navbox(context)
    debugLog('Navbox mainfuntion',context)
    local prefix, level = context.prefix, context.level
    local rootTable = mw.html.create('table')
    rootTable
        :attr('cellspacing', 0)
        :addClass('navbox')
        :css('border-spacing', 0)
        :cssText(getArg(prefix,'bodystyle'))
        :cssText(getArg(prefix,'style'))
        :tag('tr')
            :tag('td')
                :css('padding', '2px')
                :node(p.renderNavTable(context):allDone())
     debugLog('Navbox mainfuntion End')
    return rootTable
end
end
 
function p.navbox(frame)
function p.navbox(frame)
     if not getArgs then
     if not getArgs then
    getArgs = require('Module:Arguments').getArgs
        getArgs = require('Module:Arguments').getArgs
     end
     end
     args = getArgs(frame, {wrappers = 'Template:Navbox'})
     local modelArgs=getArgs(frame,{frameOnly=true})
    DEBUG = modelArgs['DEBUG'] or DEBUG
    MainTemplateName=modelArgs['MainTemplateName'] or MainTemplateName
    debugLog('Navbox start')


    args = getArgs(frame, {wrappers = MainTemplateName, trim = true})
    debugLog('getArgs done,',args)
    local prefix, level = "", 1
    local NavType = getValidType(getArg(prefix,'type') or  modelArgs['type'],NavType.V)
    DEBUG = modelArgs['DEBUG'] or DEBUG
     -- Read the arguments in the order they'll be output in, to make references number in the right order.
     -- Read the arguments in the order they'll be output in, to make references number in the right order.
     local _
     p.shakeArgs(prefix,level,NavType)
    _ = args.title
    _ = args.above
    for i = 1, 35 do
        _ = args["group" .. tostring(i)]
        _ = args["list" .. tostring(i)]
    end   
    _ = args.below


     return p._navbox(args)
     local L0Context=NavboxContext.new(prefix,level,NavType)
    local rootNode=p._navbox(L0Context)
    debugLog('rootnode build done, Navbox end')
    return tostring(rootNode:allDone())
end
end
 
return p
return p

2024年3月30日 (六) 09:49的版本

可在模块:Navbox/doc创建此模块的帮助文档

--
-- This module will implement {{Navbox}}
--

local p = {}

--Context start
local _NavboxContext={}
local NavboxContextNewObj=function(_prefix,_level,_type)
    return {
         prefix = _prefix
        ,level = _level
        ,type = _type
        ,_Context={}
    }
end

local NavboxContextMetaFunction={
     __index=function(_obj,key)
      local _key = tostring(key)
      if _key=='prefix' or _key =='level' or _key =='type' then
       return _obj[_key]
   else
         return _obj._Context[_key]
        end
    end
    ,__newindex=function(_obj,key,val)
     local _key = tostring(key)
      if _key=='prefix' or _key =='level' or _key =='type' then
       _obj[_key]=val
   else
         _obj._Context[_key]=val
        end
    end
    ,__tostring=function(_obj)
        local output={}
        table.insert(output,'prefix='.._obj.prefix)
        table.insert(output,'level='.._obj.level)
        table.insert(output,'type='.._obj.type)
        for k,v in pairs(_obj._Context) do
            table.insert(output,k..'='..v)
        end
        return 'context:{\n'..table.concat(output,",\n")..'\n}'
    end
}

_NavboxContext.new=function(prefix,level,_type)
    local _prefix = prefix or ""
    local _level = level or 1

    local newobj=NavboxContextNewObj(_prefix,_level,_type or '')
    setmetatable(newobj,NavboxContextMetaFunction)
    --[[function newobj:remove(key)
        mw.log(self)
        NavboxContext_Remove(self,key)
    end]]
    return newobj
end
--Context end

local navbarFunc = require('Module:Navbar')._navbar
local NavboxContext = _NavboxContext
local getArgs -- lazily initialized
local DEBUG=false

--全局性参数锚
local args

--常量定义 (Constant Define)
local Limit={
      vertical=35
     ,horizontal={
         col =20
        ,list=6
      }
     ,vertical_collapsible=20
     ,child=10
}

local NavType={
     V="vertical" --垂直,list
    ,H="horizontal" --水平,col
    ,VC="vertical_collapsible" --折叠垂直
}

local MainTemplateName = 'Template:NavboxV2'

---------------------------------------------------------------
--
--工具箱方法 (Util Function)
--

local function trim(s)
    return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
end

local function addNewline(s)
    if s:match('^[*:;#]') or s:match('^{|') then
        return '\n' .. s ..'\n'
    else
        return s
    end
end

---数组除重
local function removeDump(arr)
    local _t1,_t2={},{}
    for _,val in pairs(arr) do
        _t1[val]=true
    end
    --table.remove(arr)
    for key,_ in pairs(_t1) do
        table.insert(_t2,key)
    end
    return _t2
end

local function tableToString(_table)
    local outputs={}
    if type(_table)=='table' then
        for k,v in pairs(_table) do
            local output
            if type(v)=='table' then
                output=tableToString(v)
            else
                output=tostring(v)
            end
            table.insert(outputs,tostring(k).."="..output)
        end
    end
    return '{'..table.concat(outputs,",")..'}'
end

local debugLog=function(...)
    if DEBUG then
        if #arg==1 then
            mw.log(tostring(arg[1]))
            mw.log("--------------------")
        else
            for k,v in pairs(arg) do
                local pass= false or tostring(k)=='n'
                if not pass then
                    local _v=v
                    if type(v)=='table' then
                        _v=tableToString(v)
                    end
                    mw.log(tostring(_v))
                end
            end
        end
    end
end

---------------------------------------------------------------
--
--功能性方法 (Functional Function)
--

---获得有效的类型
local getValidType=function(input,defVal)
 if NavType.V==input or NavType.H==input or NavType.VC==input then
  return input
 end
 return defVal
end

---检查border判断是不是子Navbox
local borderIsChild=function(border)
 if border == 'subgroup' or border == 'child' then
  return true
 end
 return false
end

---获得参数
local getArg=function( _a , _b,defVal,context,_contextKey)
 local contextKey = _contextKey or _b
 if context and contextKey and context[contextKey] then
  --debugLog('getArg By Context',contextKey)
  return context[contextKey]
 else
  local prefix= _a~=nil and _a or ""
  local key= (_b==nil and _a~=nil) and _a or _b
  local argsKey=prefix .. (prefix=="" and "" or "-") ..key
  --debugLog('getArg By InputArg',argsKey)
  return args[ argsKey ] or defVal
 end
end

---子Navbox参数组判断
local checkHaveChild=function(prefix,valuekey)
    if getValidType(getArg(prefix, valuekey..'-'..'type'),nil) and
       borderIsChild(getArg(prefix, valuekey..'-'..'border')) then
        return true
    end
    return false
end

---获得listnum
local function getListnum(prefix,limit,contentEqList)
    debugLog("getListnum",{['prefix']=prefix,['limit']=limit})
    prefix=prefix:gsub('(-)','%%-')
    local listnums={}
    for k, v in pairs(args) do
        k = ('' .. k)
        --debugLog("getListnum,k=",k)
        local listnum =
              ( k:match('^'..prefix..(prefix=="" and "" or "%-")..'list(%d+)$') or
                k:match('^'..prefix..(prefix=="" and "" or "%-")..'list(%d+)%-')
              )or
              ( contentEqList and ( --VerticalCollapsibleTable 的 Content适配
                 k:match('^'..prefix..(prefix=="" and "" or "%-")..'content(%d+)$') or
                 k:match('^'..prefix..(prefix=="" and "" or "%-")..'content(%d+)%-')
              ) or nil)
        if listnum and tonumber(listnum)<=limit then
            listnum=tonumber(listnum)
            table.insert(listnums,listnum)
            --debugLog("getListnum,listnum=",listnum)
        end
    end
    listnums=removeDump(listnums)
    table.sort(listnums)
    debugLog('list:',listnums)
    debugLog('getListnum End')
    return listnums
end

---参数检查和摇匀
function p.shakeArgs(prefix,level)
    local _
    local list_limit=0

    _ = getArg(prefix,"title")
    _ = getArg(prefix,"above")

    if getArg(prefix,"type")==NavType.H then
       list_limit = Limit.horizontal.list
       for i = 1, Limit.horizontal.col do
           _ = getArg(prefix,"col"..tostring(i).."header")
           if checkHaveChild(prefix,"col"..tostring(i).."header") then
               p.shakeArgs((prefix=="" and "" or "-").."col"..tostring(i).."header",level+1)
           end

           _ = getArg(prefix,"col"..tostring(i))
           if checkHaveChild(prefix,"col"..tostring(i)) then
               p.shakeArgs((prefix=="" and "" or "-").."col"..tostring(i),level+1)
           end

           _ = getArg(prefix,"col"..tostring(i).."footer")
           if checkHaveChild(prefix,"col"..tostring(i).."footer") then
               p.shakeArgs((prefix=="" and "" or "-").."col"..tostring(i).."footer",level+1)
           end
       end
    end

    if getArg(prefix,"type")==NavType.V then
        list_limit = Limit.vertical
    elseif getArg(prefix,"type")==NavType.VC then
        list_limit = Limit.vertical_collapsible
    end
    for i = 1, list_limit do
        _ = getArg(prefix,"group"..tostring(i))
        _ = getArg(prefix,"list"..tostring(i))

        if checkHaveChild(prefix,"list"..tostring(i)) then
            --debugLog('shakeArgs',prefix,"list"..tostring(i))
            p.shakeArgs((prefix=="" and "" or "-").."list"..tostring(i),level+1)
        end
        if checkHaveChild(prefix,"content"..tostring(i)) then
            p.shakeArgs((prefix=="" and "" or "-").."content"..tostring(i),level+1)
        end
    end

    _ = getArg(prefix,"below")
end
---------------------------------------------------------------
--
--  元素渲染方法 (Element Render)
--

---创建表头
local function createNavTableHeader(context)
    debugLog('render TableHeader',context)
    local prefix = context.prefix
    local state ,title ,border =
             getArg(prefix,"state",nil,context)
            ,getArg(prefix,"title")
            ,getArg(prefix,"border",nil,context)
    debugLog('render TableHeader args',{['prefix']=prefix,['state']=state,['title']=title,['border']=border})

    local rootTable=
        mw.html.create('table')
            :attr('cellspacing', 0)
            :addClass('nowraplinks')
            :addClass(getArg(prefix,"bodyclass",nil,context))
            :css('border-spacing', 0)

    if title and (state ~= 'plain' and state ~= 'off') then
        rootTable
            :addClass('collapsible')
            :addClass( state or 'autocollapse')
    end

    if border == 'subgroup' or border == 'child' or border == 'none' then
        rootTable
            :addClass('navbox-subgroup')
            :cssText(getArg(prefix,"bodystyle",nil,context))
            :cssText(getArg(prefix,"style",nil,context))
    else -- regular navobx - bodystyle and style will be applied to the wrapper table
        rootTable
            :addClass('navbox-inner')
            :css('background', 'transparent')
            :css('color', 'inherit')
    end

    rootTable:cssText(getArg(prefix,"innerstyle"))

    debugLog('render TableHeader End')
    return rootTable
end

---分割行 (SplitRow)
local function renderSplitRow(rootTable,context)
    local colspan= context.splitRowcolspan or context.totalColspan
    debugLog('render SplitRow',{
        ['needAddSplitRow']=context.needAddSplitRow,
        ['colspan']=colspan,
    }
    ,context)
    if context.needAddSplitRow then
        rootTable
            :tag('tr')
                :css('height', '2px')
                :tag('td')
                    :attr('colspan',colspan)
    else
    end
    context.splitRowcolspan=colspan
    context.needAddSplitRow=true
end

---创建三键导航
local function renderNavBar(titleCell,context)
    local prefix = context.prefix
    local  navbar , state , border, name , titlestyle =
           getArg(prefix,"navbar",nil,context)
          ,getArg(prefix,"state",nil,context)
          ,getArg(prefix,"border",nil,context)
          ,getArg(prefix,"name")
          ,getArg(prefix,'titlestyle',nil,context)
    debugLog('render Navbar',
        {['prefix']=prefix,
         ['navbar']=navbar,['state']=state,
         ['border']=border,['name']=name,
         ['titlestyle']=titlestyle}
        ,context
    )
    -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
    -- or right to keep the title centered.
    local spacerSide = nil

    if navbar == 'off' then
        -- No navbar, and client wants no spacer, i.e. wants the title to be shifted to the left. If there's
        -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
        if state == 'plain' then spacerSide = 'right' end
    elseif navbar == 'plain' or
        (   not name and
            mw.getCurrentFrame():getParent():getTitle() == MainTemplateName and
            (border == 'subgroup' or border == 'child' or border == 'none')
        )
        then
        -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
            if state ~= 'plain' then spacerSide = 'left' end
    else
        -- Will render navbar (or error message). If there's no show/hide link, need a spacer on the right
        -- to balance out the width of the navbar.
        if state == 'plain' then spacerSide = 'right' end

        titleCell:wikitext(navbarFunc{
            name,
            mini = 1,
            fontstyle = table.concat(
            {
                  getArg(prefix,'basestyle',nil,context) or ''
                 ,(titlestyle or '')
                 ,'background:none transparent;border:none'
            }
            ,';')
        })
    end

    -- Render the spacer div.
    if spacerSide then
        titleCell
            :tag('span')
                :css('float', spacerSide)
                :css('width', '8em')
                :css('font-size', '80%')
                :css('margin-' .. (spacerSide == 'left' and 'right' or 'left'), '0.5em')
                :wikitext('&nbsp;')
    end

    debugLog('render Navbar End')
end

---标题行
local function renderTitleRow(rootTable,context)
    local prefix = context.prefix
    local title = getArg(prefix,"title",nil,context)
    if not title then return end
    debugLog('render TitleRow',{['prefix']=prefix,['title']=title},context)
    local basestyle = getArg(prefix,"basestyle",nil,context)
    renderSplitRow(rootTable,context)
    local titleRow=rootTable:tag('tr')

    local titlegroup=getArg(prefix,"titlegroup")
    if titlegroup and (not context.notNeedTitlegroup) then
        titleRow
            :tag('th')
                :attr('scope', 'row')
                :addClass('navbox-group')
                :addClass(getArg(prefix,"titlegroupclass"))
                :cssText(basestyle)
                :cssText(getArg(prefix,"groupstyle",nil,context))
                :cssText(getArg(prefix,"titlegroupstyle"))
                :wikitext(titlegroup)
    end

    local titleCell = titleRow:tag('th'):attr('scope', 'col')
    local titleStyle = getArg(prefix,"titlestyle",nil,context)
    local titleColspan = context.totalColspan
    if titlegroup and (not context.notNeedTitlegroup) then
        titleCell
            :css('border-left', '2px solid #fdfdfd')
            :css('width', '100%')

        titleColspan = titleColspan - 1
    end
    titleCell
        :cssText(basestyle)
        :cssText(titleStyle)
        :addClass('navbox-title')
        :addClass(getArg(prefix,"titleclass",nil,context))
        :attr('colspan', titleColspan)

    renderNavBar(titleCell,context)

    titleCell
         :tag('div')
             :css('font-size', '110%')
             :wikitext(addNewline(title))

    debugLog('render TitleRow End')
end

---上列
local function renderAboveRow(rootTable,context)
    local prefix = context.prefix
    local above = getArg(prefix,"above")
    if not above then return end
    debugLog('render AboveRow',{['prefix']=prefix},context)
    renderSplitRow(rootTable,context)

    local Colspan=context.totalColspan
    local AboveRow=rootTable:tag('tr')
    AboveRow
        :tag('td')
            :addClass('navbox-abovebelow')
            :addClass(getArg(prefix,"aboveclass"))
            :cssText(getArg(prefix,"basestyle"))
            :cssText(getArg(prefix,"abovestyle"))
            :attr('colspan', Colspan)
            :tag('div')
                :wikitext(addNewline(above))

    debugLog('render AboveRow End')
end

---下列
local function renderBelowRow(rootTable,context)
    local prefix = context.prefix
    local below = getArg(prefix,"below")
    if not below then return end
    debugLog('render BelowRow',{['prefix']=prefix},context)
    renderSplitRow(rootTable,context)

    local Colspan=context.totalColspan
    local BelowRow=rootTable:tag('tr')
    BelowRow
        :tag('td')
            :addClass('navbox-abovebelow')
            :addClass(getArg(prefix,"belowclass"))
            :cssText(getArg(prefix,"basestyle"))
            :cssText(getArg(prefix,"belowstyle"))
            :attr('colspan', Colspan)
            :tag('div')
                :wikitext(addNewline(below))

    debugLog('render BelowRow End')
end

---------------------------------------------------------------

--数据列的方法生成器
local function _renderColRow_FunctionBuilder(rootTable,context,nodeFunc)
    debugLog("_renderColRow_FunctionBuilder builded",{['context']=context})
    return function(listCellDivToWrite,divNotClose)
        debugLog(debug.traceback('FunctionInrenderColRow'),{['context']=context,['divNotClose']=divNotClose})
        if not divNotClose then
          listCellDivToWrite:done()--div end
          :node(
              rootTable and nodeFunc(rootTable,context) or
              nodeFunc(context)
          )
          :tag('div'):done()
        else
          listCellDivToWrite:node(nodeFunc(rootTable,context))
        end
    end
end

---数据行,统一的实现
local function _renderListRow(rootTable,context,OtherListFunction)
    renderSplitRow(rootTable,context)

    local prefix, level = context.prefix, context.level
    local listnum = context.listnum or 1
    local isFirst, isOdd = (listnum==1) ,(listnum % 2) == 1
    local ImageRowspan = 2 * context.totalRowspan - 1 + ( context['imageCellCompensate'] or 0)
    local notNeedImage, notNeedGroup =
             context.notNeedImage
            ,context.notNeedGroup
    debugLog('ValueRow Implement',
            {['prefix']=prefix,
            ['listnum']=listnum,
            ['ImageRowspan']=ImageRowspan,
            ['HaveOtherListFunction']=tostring(not not OtherListFunction),
            ['notNeedImage']=notNeedImage,
            ['notNeedGroup']=notNeedGroup},
            context)
    local listRow=rootTable:tag('tr')
    local groupCell,listCell
    local insertImage=false

    --image
    local  imageLeft , image , insertImage =
                 getArg(prefix,"imageleft",nil,context)
                ,getArg(prefix,"image",nil,context)
                ,false
    --CollapsibleListRow 适配
    if context.notImageLeftCell then
        imageLeft = nil
    end
    if context.notImageCell then
        image = nil
    end
    if isFirst and (not notNeedImage) then
        if imageLeft then
            debugLog('imageLeftRow',{['imageLeft']=imageLeft})
            listRow:tag('td')--[[,{['parent']=listRow}]]
             :addClass('navbox-image')
             :addClass(getArg(prefix,"imageclass",nil,context))
             :css('width', '0%')
             :css('padding', '0px 2px 0px 0px')
             :cssText(getArg(prefix,"imageleftstyle",nil,context))
             :attr('rowspan', ImageRowspan)
             :tag('div')
                 :wikitext(addNewline(imageLeft))
             :done() --div done
            :done() --td done
        end
        if image then
          insertImage=true
        end
    end

    --list pre
    local listHaveChild = checkHaveChild(prefix,'list'..listnum)
    local contentHaveChild = context.contentEqList and checkHaveChild(prefix,'content'..listnum)

    --group
    local  group, groupwidth , grouppadding , removeGroupPadding =
             getArg(prefix,"group"..listnum,nil,context)
            ,( ( group and getArg(prefix,"groupwidth") ) or nil )
            ,( getArg(prefix,"grouppadding") or '0em 0.75em;' )
            ,( getArg(prefix,'removeGroupPadding',false) and level > 1 )
    if group and not notNeedGroup then
        debugLog('groupTh',{['group']=group})
        groupCell=listRow:tag('th')
            :attr('scope', 'row')
            :addClass('navbox-group')
            :addClass(getArg(prefix,"groupclass",nil,context))
            :cssText(getArg(prefix,"basestyle"))
            :css((( groupwidth and {['width']=groupwidth}) or {}))
            :cssText(getArg(prefix,"groupstyle"))
            :cssText(getArg(prefix,'group' .. listnum .. 'style'))
        local tempEle=groupCell
        if (borderIsChild(getArg(prefix,"border"))) and (getArg(prefix,'type')==NavType.V) and (not removeGroupPadding) then --针对列式子组合的适配
         groupCell:cssText("padding-left:0em;padding-right:0em;")

         tempEle=tempEle:tag("div"):css("padding",grouppadding)
        end
        tempEle:wikitext(group)

    end

    --list
    do
        listCell=listRow:tag('td')
        if group and not notNeedGroup then
            listCell
                :css('text-align', 'left')
                :css('border-left-width', '2px')
                :css('border-left-style', 'solid')
        else
            listCell:attr('colspan', 2)
        end

        if not groupwidth then
            listCell:css('width', '100%')
        end

        local evenOdd = getArg(prefix,"evenodd")
        evenOdd = (
            evenOdd == 'swap' and
            (isOdd and 'even' or 'odd') or
            (isOdd and (evenOdd or 'odd') or (evenOdd or 'even'))
        )
        local evenOddStyle=(isOdd and getArg(prefix,"evenstyle")) or getArg(prefix,"oddstyle")
        if context.lockEvenOdd then --CollapsibleListRow 适配
            evenOdd='odd'
        end
        if context.noEvenOddStyle then --CollapsibleListRow 适配
         evenOddStyle=''
        end

        local list1padding = (notNeedGroup) and getArg(prefix,"list1padding",nil,context) or
                             '0em 0.25em'
        local listNpadding = (isFirst and list1padding) or
                             ( getArg(prefix,"listpadding",nil,context) or '0em 0.25em' )
        local listNstyle= --((not notNeedGroup))
                        (isFirst and getArg(prefix,'list1style','',context) ) or
                        getArg(prefix,'list'..listnum .. 'style','')
        local liststyle = getArg(prefix,"liststyle",'',context)

  listCell
            :css('padding', '0px')
            :cssText(liststyle)
            :cssText(evenOddStyle)
            :cssText(listNstyle)
            :addClass('navbox-list')
            :addClass('navbox-' .. evenOdd)
            :addClass(getArg(prefix,"listclass"))
        local tempdiv=listCell:tag('div'):css('padding', listNpadding)
        --local listHaveChild = checkHaveChild(prefix,'list'..listnum)
        --local contentHaveChild = context.contentEqList and checkHaveChild(prefix,'content'..listnum)
        if OtherListFunction then
            debugLog('ValueRow OtherListFunction',{['otherListFunctionDivNotClose']=context.otherListFunctionDivNotClose})
            --OtherListFunction(listCell)
            OtherListFunction(tempdiv,context.otherListFunctionDivNotClose)
        elseif (listHaveChild or contentHaveChild) and level<= Limit.child then
            local listKeyName='list'
            if contentHaveChild then
                listKeyName='content'
            end
            local childContext=NavboxContext.new(
                 prefix..(prefix=='' and '' or '-')..listKeyName..listnum ,
                 level+1 ,
                 getValidType(
                     getArg(prefix..(prefix=='' and '' or '-')..
                                   listKeyName..listnum,'type'),
                     NavType.V
                 )
            )
            debugLog('ValueRow NewChild',childContext)
            tempdiv:done()-- div end
                :node(p.renderNavTable(childContext))
                :tag('div'):done()
        else
            local listContent = getArg(prefix,'list'..listnum,'')..
                           ( ((not context.contentEqList ) and '') or getArg(prefix,'content' .. listnum,''))
            debugLog('ValueRow listnum',{['listnum']=listnum})
            tempdiv:wikitext(addNewline(listContent))
        end
    end
    --end

    if insertImage then
      debugLog('imageRow',{['image']=image})
      listRow:tag('td')
          :addClass('navbox-image')
          :addClass(getArg(prefix,"imageclass",nil,context))
          :css('width', '0%')
          :css('padding', '0px 0px 0px 2px')
          :cssText(getArg(prefix,"imagestyle",nil,context))
          :attr('rowspan', ImageRowspan)
          :tag('div')
              :wikitext(addNewline(image))
    end
    debugLog('ValueRow Implement End')
end

---数据行,垂直式的具体实现
local function renderListRow(rootTable,context)
    debugLog('render ListRow',context)
    _renderListRow(rootTable,context)
    debugLog('render ListRow End')
end

---------------------------------------------------------------

---数据列,水平式的具体实现 (ColRow)
local function _renderColRow(rootTable,context)
    local prefix, level = context.prefix, context.level
    local fullwidth  =getArg(prefix,"fullwidth")
    local col1header,col1,col1footer=
           getArg(prefix,'col'..'1'..'header')
          ,getArg(prefix,'col'..'1')
          ,getArg(prefix,'col'..'1'..'footer')
    debugLog('ColRow Implement',{['prefix']=prefix},context)
    --new table root
    rootTable=mw.html.create('table')
    rootTable
        :addClass("navbox-columns-table")
        :attr("cellspacing","0")
        :cssText("text-align:left;")
        :cssText( ( col1header or fullwidth ) and
            "width:100%;" or
            "width:auto;margin-left:auto;margin-right:auto;"
        )
        :cssText(getArg(prefix,"coltablestyle"))

    local headerTR,colbodyTR,footerTR=nil,nil,nil

    context.needAddSplitRow=false
    context.splitRowcolspan=1
    --header
    if col1header then
        renderSplitRow(rootTable,context)
        debugLog('ColRow Header',{})
        headerTR=rootTable:tag('tr')
        for colnum=1,Limit.horizontal.col do
            debugLog('ColRow Header',colnum)
            local isFirst,isOdd = colnum == 1, (colnum % 2) == 1
            local colheaderkey='col'..colnum..'header'
            local colNheader= isFirst and col1header or getArg(prefix,colheaderkey)

            if  headerTR  and colNheader then
                debugLog('ColRow Herder Cell',{['colnum']=colnum})
                local headerNCell=headerTR:tag('td')
                headerNCell
                    :addClass('navbox-abovebelow')
                    :cssText(isFirst and "" or "border-left:2px solid #fdfdfd;")
                    :cssText(getArg(prefix, "colheaderstyle"))
                    :cssText(getArg(prefix, colheaderkey..'style'))
                    :attr(( colnum~=Limit.horizontal.col and {['colspan']=getArg(prefix,colheaderkey..'colspan',1)} ) or {})
--[[                if checkHaveChild(prefix,colheaderkey) and level<= Limit.child then
                    local childContext=NavboxContext.new(colheaderkey ,level+1 ,NavType.H)
                    debugLog('ColRow Herder NewChild',childContext)
                    headerNCell:node(p.renderNavTable(childContext):allDone())
                else]]
                    --debugLog('ColRow Herder Cell',{['colnum']=colnum})
                    --headerNCell
                    :wikitext(addNewline("'''"..colNheader.."'''"))
                --end
            end
        end
        debugLog('ColRow Header End',{['colnum']=colnum})
    end

    --col
    local col1havechild = checkHaveChild(prefix,"col1")
    if col1 or col1havechild then
        renderSplitRow(rootTable,context)
        debugLog('ColRow Body',{
         ['col1havechild']=col1havechild
        })
        colbodyTR=rootTable:tag('tr'):cssText('vertical-align:top;')
        if not(col1header or col1footer or fullwidth) then
            local padding,test0=getArg(prefix, "padding"),nil
            if padding then
                padding = trim(padding)
                test0=padding:find('^0[%%%a]?[%a]?[;]?$')
            end
            if test0~=nil or padding=='off' then else
                colbodyTR
                    :tag('td')
                        :css("width", padding or '5em')
                        :wikitext('&nbsp;&nbsp;&nbsp;')
                    :done()
            end
        end
        for colnum=1,Limit.horizontal.col do
            debugLog('ColRow Body',colnum)
            local isFirst,isOdd = colnum == 1, (colnum % 2) == 1
            local colkey = 'col'..colnum
            local colN = isFirst and col1 or getArg(prefix,colkey)
            local colNhavechild = isFirst and col1havechild or
                                  checkHaveChild(prefix,colkey)
            if  colN or colNhavechild then
                local oddevenstyle = getArg( prefix , isOdd and 'oddcolstyle' or 'evencolstyle')
                local colNCell=colbodyTR
                    :tag('td')
                    :css("padding","0px")
                    :cssText(((not isFirst) and "border-left:2px solid #fdfdfd;" ) or '')
                    :cssText(getArg(prefix,'colstyle'))
                    :cssText(oddevenstyle)
                    :cssText(getArg(prefix, colkey..'style'))
                    :css('width', ( getArg(prefix, colkey..'width') or getArg(prefix,'colwidth') ) or '10em')

                if checkHaveChild(prefix,colkey) and level<= Limit.child then
                    local childContext=NavboxContext.new(prefix..(prefix=='' and '' or '-')..colkey ,level+1 ,getValidType(getArg(prefix,'type'),NavType.H))
                    debugLog('ColRow Body NewChild',childContext)
                    colNCell:tag('div'):done()
                    :node(p.renderNavTable(childContext):allDone())
                    :tag('div'):done()
                else
                    debugLog('ColRow Body Cell',{['colnum']=colnum})
                    colNCell:tag('div'):wikitext(addNewline(colN))
                end
            end
            debugLog('ColRow Body End',{['colnum']=colnum})
        end
    end

    --footer
    if col1footer then
        renderSplitRow(rootTable,context)
        debugLog('ColRow footer',{})
        footerTR=rootTable:tag('tr')
        for colnum=1,Limit.horizontal.col do
            debugLog('ColRow footer',colnum)
            local isFirst,isOdd = colnum == 1, (colnum % 2) == 1
            local colfooterkey='col'..colnum..'footer'
            local colNfooter=isFirst and col1footer or getArg(prefix,colfooterkey)

            if colNfooter then
                debugLog('ColRow footer Cell',{['colnum']=colnum})
                local footerNCell=footerTR:tag('td')
                footerNCell
                    :addClass('navbox-abovebelow')
                    :cssText(isFirst and "" or "border-left:2px solid #fdfdfd;")
                    :cssText(getArg(prefix, "colfooterstyle"))
                    :cssText(getArg(prefix, colfooterkey..'style'))
                    :attr(( colnum~=Limit.horizontal.col and {['colspan']=getArg(prefix,colfooterkey..'colspan',1)}) or {})
--[[                if checkHaveChild(prefix,colfooterkey) and level<= Limit.child then
                    local childContext=NavboxContext.new(colfooterkey ,level+1 ,NavType.H)
                    debugLog('ColRow footer NewChild',childContext)
                    footerNCell:node(p.renderNavTable(childContext):allDone())
                else]]
                    --debugLog('ColRow footer Cell',{['colnum']=colnum})
                    --footerNCell
                    :wikitext(addNewline("'''"..colNfooter.."'''"))
                --end
            end
        end
        debugLog('ColRow footer End',{['colnum']=colnum})
    end

    debugLog('ColRow Implement End')
    return rootTable:allDone()
end

--数据列,具体实现
local function renderColRow(rootTable,context)
    debugLog('renderColRow',{['context']=context})

    context.notNeedGroup = true
    context['list1padding']='0px'
    context['list1style']="background:transparent;color:inherit;"
    context['otherListFunctionDivNotClose']=true
    context['imageCellCompensate']=2

    _renderListRow(
        rootTable,context,
        _renderColRow_FunctionBuilder(rootTable,context,_renderColRow)
    )
    
    --clean up
    context.notNeedGroup=nil
    context['list1padding']=nil
    context['list1style']=nil
    context['otherListFunctionDivNotClose']=nil
    context['imageCellCompensate']=nil
    debugLog('renderColRow End')
end

---------------------------------------------------------------

--折叠行式的子Nabox
local function _renderSmallNavboxInCollapsibleListRow(rootTable,context)
    local prefix, level = context.prefix, context.level
    debugLog('_renderSmallNavboxInCollapsibleListRow',{['prefix']=prefix},{['context']=context})
    local listnum = context.listnum

    --部分需要压制传入的样式
    context.bodyclass = ''
    context.titleclass = ''
    context.groupclass = ''
    context.imageclass = ''
    context.bodystyle = ''
    context.style = ''
    context.basestyle = ''
    context.imagestyle = ''
    context.imageleftstyle = ''

    --传入renderNavBar,renderTitleRow
    context.navbar='plain'
    context.border='child'
    local selected , abbrN , state =
          getArg(prefix,'selected') , getArg(prefix,'abbr'..listnum) , 'uncollapsed'
    if selected ~= nil and selected == abbrN then
      state='uncollapsed'
    else
      state=getArg(prefix,'state'..listnum,'collapsed')
    end
    context.state = state

    --传入renderTitleRow
    --context.titleEqGroup=true
    context.notNeedTitlegroup=true
    context.titlestyle=table.concat(
    {
          (getArg(prefix,'basestyle','')                  )
         ,(getArg(prefix,'groupstyle','')                 )
         ,(getArg(prefix,'secttitlestyle','')             )
         ,(getArg(prefix,'group'..listnum..'style','')    )
         ,(getArg(prefix,'sect'..listnum..'titlestyle',''))
    }
    ,';')
    context.title=(getArg(prefix,'group'..listnum,'')  )..
                  (getArg(prefix,'sect'..listnum,'')   )..
                  (getArg(prefix,'section'..listnum,''))

    --传入renderListRow
    context.contentEqList=true
    context.notNeedGroup=true
    context.liststyle=table.concat(
    {
          (getArg(prefix,'liststyle','')                )
         ,(getArg(prefix,'contentstyle','')             )
         ,(getArg(prefix,'list'..listnum..'style','')   )
         ,(getArg(prefix,'content'..listnum..'style',''))
    }
    ,';')
    local totalColspan=2 --title,above,below
    local totalRowspan=1 --image,imageleft
    --传入image
    local  imageLeft,image=
                 getArg(prefix,"imageleft"..listnum,nil,context,'imageleft')
                ,getArg(prefix,"image"..listnum,nil,context,'image')
    if imageLeft then
     totalColspan = totalColspan + 1
     context.imageleft = imageLeft
    else
     context.notImageLeftCell=true --CollapsibleListRow 适配
    end
    if image then
     totalColspan = totalColspan + 1
     context.image = image
    else
     context.notImageCell=true --CollapsibleListRow 适配
    end

    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    context.splitRowcolspan = totalColspan
    context.lockEvenOdd=true --CollapsibleListRow 适配

    debugLog('SmallNavboxInCollapsibleListRow Implement','listnum='..listnum,context)
    --start
    local rootTable2 = createNavTableHeader(context)
    renderTitleRow(rootTable2,context)
    --only 1 list
    local otherListFunction
    local listHaveChild = checkHaveChild(prefix,'list'..listnum)
    local contentHaveChild = context.contentEqList and checkHaveChild(prefix,'content'..listnum)
    if (listHaveChild or contentHaveChild) and level<= Limit.child then
        local listKeyName='list'
        if contentHaveChild then
            listKeyName='content'
        end
        local childContext=NavboxContext.new(
                               prefix..(prefix=='' and '' or '-')..listKeyName..listnum ,
                               level+1 ,
                               getValidType(getArg(prefix..(prefix=='' and '' or '-')..listKeyName..listnum,'type'),NavType.V))
        debugLog('SmallNavboxInCollapsibleListRow NewChild',childContext)
        otherListFunction=_renderColRow_FunctionBuilder(nil,childContext,p.renderNavTable)
    end
    context.noEvenOddStyle=true
    _renderListRow(rootTable2,context,otherListFunction)
    context.noEvenOddStyle=nil
    debugLog('_renderSmallNavboxInCollapsibleListRow End')
    return rootTable2:allDone()
end

---折叠行具体实现
local function renderCollapsibleListRow(rootTable,context)
   local prefix, level = context.prefix, context.level
   debugLog('renderCollapsibleListRow',{['prefix']=prefix},{['context']=context})
   context.notNeedGroup = true
   local listnum = context.listnum
   local context_function
   if getArg(prefix,'group'..listnum)   or
      getArg(prefix,'sect'..listnum)    or
      getArg(prefix,'section'..listnum) then
        local grandChild_context=NavboxContext.new(prefix,level)
        grandChild_context.notNeedGroup=true
        grandChild_context.listpadding=getArg(prefix,'listpadding')
        grandChild_context.listnum=listnum
        context_function=_renderColRow_FunctionBuilder(
            rootTable,grandChild_context,
            _renderSmallNavboxInCollapsibleListRow
        )
        debugLog('renderCollapsibleListRow function generate',{['context']=context,['grandChild_context']=grandChild_context})
    end
    context.noEvenOddStyle=true
    debugLog('renderCollapsibleListRow renderListRow',{['context']=context})
    _renderListRow(rootTable,context,context_function)
    context.noEvenOddStyle=nil
    debugLog('renderCollapsibleListRow End')
end

---------------------------------------------------------------
--
--   Tracking categories
--
local function needsHorizontalLists(context)
    local prefix = context.prefix
    local border ,listclass ,bodyclass =
             context.border    or getArg(prefix,'border')
            ,context.listclass or getArg(prefix,'listclass')
            ,context.bodyclass or getArg(prefix,'bodyclass')

    if borderIsChild(border)
        or getArg(prefix,'tracking') == 'no' then
        return false
    end

    local listClasses = {'plainlist', 'hlist', 'hlist hnum', 'hlist hwrap', 'hlist vcard', 'vcard hlist', 'hlist vevent', 'hlist hlist-pipe'}
    for i, cls in ipairs(listClasses) do
        if listclass == cls or bodyclass == cls then
            return false
        end
    end

    return true
end

local function hasBackgroundColors(context)
    local prefix = context.prefix
    local titlestyle ,groupstyle ,basestyle =
             context.titlestyle or getArg(prefix,'titlestyle')
            ,context.groupstyle or getArg(prefix,'groupstyle')
            ,context.basestyle  or getArg(prefix,'basestyle')
    return mw.ustring.match(titlestyle or '','background') or
           mw.ustring.match(groupstyle or '','background') or
           mw.ustring.match(basestyle  or '','background')
end

local function argNameAndRealTitleAreDifferent(context)
    local prefix = context.prefix
    local border ,name =
             getArg(prefix,'border',nil,context)
            ,getArg(prefix,'name',nil,context)
    if borderIsChild(border)
        or getArg(prefix,'tracking') == 'no' then
        return false
    end

    if name ~= mw.title.getCurrentTitle().text then
        return true
    end
    return false
end

local function getTrackingCategories(context)
    local cats = {}
    if needsHorizontalLists(context) then table.insert(cats, '没有使用水平列表的导航框') end
    if hasBackgroundColors(context) then table.insert(cats, '使用背景颜色的导航框') end
    if argNameAndRealTitleAreDifferent(context) then table.insert(cats, 'name參數和實際不同的導航框') end
    return cats
end

local function renderTrackingCategories(builder,context)
    local title = mw.title.getCurrentTitle()
    if title.namespace ~= 10 then return end -- not in template space
    local subpage = title.subpageText
    if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end

    for i, cat in ipairs(getTrackingCategories(context)) do
        builder:wikitext('[[Category:' .. cat .. ']]')
    end
end

---------------------------------------------------------------
--
--  SubType Implement
--

---水平式
local function renderHorizontalTable(context)
    debugLog('render Horizontal NavTable',context)
    local prefix, level = context.prefix, context.level

    local rootTable = createNavTableHeader(context)

    local listnums=getListnum(prefix,Limit.horizontal.list)

    local totalColspan=2 --title,above,below
    local totalRowspan=#listnums --image,imageleft
    if getArg(prefix,"imageleft",nil,context) then totalColspan =totalColspan + 1 end
    if getArg(prefix,"image",nil,context) then totalColspan =totalColspan + 1 end
    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    --context.splitRowcolspan = totalColspan

    renderTitleRow(rootTable,context)
    renderAboveRow(rootTable,context)

    if listnums==nil or #listnums==0 then --没有list的话,只有col
     debugLog('render Horizontal NavTable,no list',{listnums})
     context.listnum=1
     renderColRow(rootTable,context)
     --context.notNeedImage=true
     context.splitRowcolspan = totalColspan
    else
     debugLog('render Horizontal NavTable,have list with col',{listnums})
     for i,listnum in ipairs(listnums) do
         context.listnum=listnum
         if listnum==1 then
           --一行Col
           renderColRow(rootTable,context)
           context.notNeedImage=true
           context.splitRowcolspan = totalColspan
         else
           context.notNeedImage=nil
         end
         _renderListRow(rootTable,context)
     end
    end
    renderBelowRow(rootTable,context)

    renderTrackingCategories(rootTable,context)
    debugLog('render Horizontal NavTable End')
    return rootTable
end

---垂直式
local function renderVerticalTable(context)
    debugLog('render Vertical NavTable',context)
    local prefix, level = context.prefix, context.level

    local rootTable = createNavTableHeader(context)

    local listnums=getListnum(prefix,Limit.vertical)

    local totalColspan=2 --title,above,below
    local totalRowspan=#listnums --image,imageleft
    if getArg(prefix,"imageleft",nil,context) then totalColspan =totalColspan + 1 end
    if getArg(prefix,"image",nil,context) then totalColspan =totalColspan + 1 end
    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    --context.splitRowcolspan = totalColspan

    renderTitleRow(rootTable,context)
    renderAboveRow(rootTable,context)
    for i,listnum in ipairs(listnums) do
        context.listnum=listnum
        renderListRow(rootTable,context)
    end
    renderBelowRow(rootTable,context)

    renderTrackingCategories(rootTable,context)
    debugLog('render Vertical NavTable End')
    return rootTable
end

---垂直折叠式
local function renderVerticalCollapsibleTable(context)
    debugLog('render VerticalCollapsible NavTable',context)
    local prefix, level = context.prefix, context.level

    local rootTable = createNavTableHeader(context)

    local listnums=getListnum(prefix,Limit.vertical
      ,(--[[context.contentEqList or ]]true) --VerticalCollapsibleTable 的 Content适配
    )

    local totalColspan=2 --title,above,below
    local totalRowspan=#listnums --image,imageleft
    if getArg(prefix,"imageleft",nil,context) then totalColspan =totalColspan + 1 end
    if getArg(prefix,"image",nil,context) then totalColspan =totalColspan + 1 end
    context.totalColspan = totalColspan
    context.totalRowspan = totalRowspan
    --context.splitRowcolspan = totalColspan

    renderTitleRow(rootTable,context)
    renderAboveRow(rootTable,context)
    for i,listnum in ipairs(listnums) do
        context.listnum=listnum
        renderCollapsibleListRow(rootTable,context)
    end
    renderBelowRow(rootTable,context)

    renderTrackingCategories(rootTable,context)
    debugLog('render VerticalCollapsible NavTable End')
    return rootTable
end

---Type Selector
function p.renderNavTable(context)
    local navtype  = context.type
    debugLog('render NavTable')
    debugLog('Type='..navtype)
    local result
    if navtype==NavType.H then
        result=renderHorizontalTable(context)
    elseif navtype==NavType.VC then
        result=renderVerticalCollapsibleTable(context)
    else
        result=renderVerticalTable(context)
    end
    debugLog('render NavTable End')
    return result
end

--Main Funtion
function p._navbox(context)
    debugLog('Navbox mainfuntion',context)
    local prefix, level = context.prefix, context.level
    local rootTable = mw.html.create('table')
    rootTable
        :attr('cellspacing', 0)
        :addClass('navbox')
        :css('border-spacing', 0)
        :cssText(getArg(prefix,'bodystyle'))
        :cssText(getArg(prefix,'style'))
        :tag('tr')
            :tag('td')
                :css('padding', '2px')
                :node(p.renderNavTable(context):allDone())
    debugLog('Navbox mainfuntion End')
    return rootTable
end

function p.navbox(frame)
    if not getArgs then
        getArgs = require('Module:Arguments').getArgs
    end
    local modelArgs=getArgs(frame,{frameOnly=true})
    DEBUG = modelArgs['DEBUG'] or DEBUG
    MainTemplateName=modelArgs['MainTemplateName'] or MainTemplateName
    debugLog('Navbox start')

    args = getArgs(frame, {wrappers = MainTemplateName, trim = true})
    debugLog('getArgs done,',args)

    local prefix, level = "", 1
    local NavType = getValidType(getArg(prefix,'type') or  modelArgs['type'],NavType.V)
    DEBUG = modelArgs['DEBUG'] or DEBUG
    -- Read the arguments in the order they'll be output in, to make references number in the right order.
    p.shakeArgs(prefix,level,NavType)

    local L0Context=NavboxContext.new(prefix,level,NavType)
    local rootNode=p._navbox(L0Context)
    debugLog('rootnode build done, Navbox end')
    return tostring(rootNode:allDone())
end

return p