模組:NavboxV2/sandbox

文档图示 模块文档[查看] [编辑] [历史] [清除缓存]

这是{{NavboxV2}}的Lua实现代码。

简介

合并了{{Navbox}}相关的一系列模板。融合了{{Navbox}}的行式、{{Navbox subgroup}}的子代模块包含、{{Navbox with columns}}的列式,{{Navbox with collapsible groups}})的折叠行式。

改写自模块:Navbox(oldid=42280913)。

设计用途

Category:引用模板后大小超过限制的页面中,有相当一部分页面是由于{{Navbox}}模板超载导致。

  • 根据WP:模板限制中“嵌套展开”的说法,相同页面的多次嵌套调用是会被分次统计的(例如:页面A嵌入页面B,页面B嵌入页面C,页面C相对页面A统计到的展开字节数是被计算了2次)。而现在Navbox的子代块、列式,折叠行式的实现都是基于Navbox行式的模板调用或类似样式结构迭代,这样就符合内部多次调用Navbox的条件,页面很容易会超过模版展开后大小的限制。
  • 其次,实际上Lua的运行限制条件相当宽裕,50MB的内存限制,10秒的运行时限制,很多页面实际使用只在十分之一左右或以下,可以被大量压榨性能。

所以将Navbox所有的实现全部以Lua实现,希望能腾出解释器运行量到Lua运行量,降低解析器触发展开后大小限制的可能。

效果

在对于包含一层子Navbox的情况,展开后大小下降最多有50~60%左右。

对比例子

项目 {{Navbox}}系列,参考基准 本模板
Template:哈利波特 Special:固定链接/60036259 User:Cwek/工作室2/Navbox/T:哈利波特
Template:广州 Special:固定链接/60035252 User:Cwek/工作室2/Navbox/T:广州
Template:广州地铁车站 Special:固定链接/59586101 User:Cwek/工作室2/Navbox/T:广州地铁
Template:粵港澳大灣區公共交通 Special:固定链接/59654656 User:Cwek/工作室2/Navbox/T:粵港澳大灣區公共交通
Template:JR東日本的車輛 Special:固定链接/61531803 Special:固定链接/62385808
Template:中华人民共和国广播电视付费频道 Special:固定链接/77500465 Special:固定链接/77504799

参数

与{{Navbox}}系列模板基本兼容。但新增部分参数填入:

  • type:Navbox的类型,对应值为vertical(对应{{Navbox}})、horizontal(对应{{Navbox with columns}})、vertical_collapsible(对应{{Navbox with collapsible groups}}),默认值为vertical
  • border:Navbox的隐藏参数,用于控制Navbox的边框机制,来使子Navbox能被嵌入到父Navbox的值字段(例如listcol等)中,实际对应{{Navbox subgroup}}或{{Navbox|child}}的实现机制。对应值为childsubgroup任一个。
在本模板添加子Navbox层时,必须传入这两个参数,这是本模板区分是否存在子Navbox层的依赖。本模板首层Navbox层无需添加border,按需添加type
  • removeGroupPadding:用于区别{{Navbox|child}}和{{Navbox subgroup}},后者在Groupn字段的单元格增加一组padding的配置,适用于子Navbox层。任意值,存在则可,为移除该padding配置(对应{{Navbox|child}})。

方便复制的代码:

| <list/content>-type = vertical | horizontal | vertical_collapsible
| <list/content>-border = child| subgroup 

自{{Navbox}}系列模板转换

将原有嵌入{{Navbox}}系列模板的值字段listn(其他类同)改为listn-,并作为相应嵌套子Navbox模板的参数的前缀来加入,使这些模板嵌套转换为扁平化的一层模板参数。

例子
{{Navbox}}系列 本模板
{{Navbox
|name = Navbox/doc
|state = expanded
|image = {{{image}}}
|imageleft = {{{imageleft}}}
|title = {{{title}}}
|above = {{{above}}}
|group1 = {{{group1}}}
|list1 = {{Navbox subgroup
 | title = {{{list1-title}}}
 | above = {{{list1-above}}}
 | below = {{{list1-below}}}
 | imageleft = {{{list1-imageleft}}}
 | image = {{{list1-image}}}
 | group1 = {{{list1-group1}}}
 | list1  = {{{list1-list1}}}
 | group2 = {{{list1-group2}}}
 | list2  = {{{list1-list2}}}
}}
|group2 = {{{group2}}}
|list2 = {{Navbox subgroup
| group1 = {{{list2-group1}}}
| list1  = {{{list2-list1}}}
| group2 = {{{list2-group2}}}
| list2  = {{{list2-list2}}}
}}
|below = {{{below}}}
}}
{{NavboxV2
|name = Navbox/doc
|state = expanded
|image = {{{image}}}
|imageleft = {{{imageleft}}}
|title = {{{title}}}
|above = {{{above}}}
<!--  list1 -->
|group1 = {{{group1}}}
<!-- list1-sub-->
|list1-type =vertical <!--作为list1的子Navbox层,全部相应参数加上对应前缀“list1-”,下同,如此类推 -->
|list1-border=child
|list1-title = {{{list1-title}}}
|list1-above = {{{list1-above}}}
|list1-below = {{{list1-below}}}
|list1-imageleft = {{{list1-imageleft}}}
|list1-image = {{{list1-image}}}
|list1-group1 = {{{list1-group1}}}
|list1-list1  = {{{list1-list1}}}
|list1-group2 = {{{list1-group2}}}
|list1-list2  = {{{list1-list2}}}
<!--  list2 -->
|group2 = {{{group2}}}
<!-- list2-sub-->
|list2-type =vertical <!--作为list2的子Navbox层,全部相应参数加上对应前缀“list2-”,下同,如此类推 -->
|list2-border=child
|list2-group1 = {{{list2-group1}}}
|list2-list1  = {{{list2-list1}}}
|list2-group2 = {{{list2-group2}}}
|list2-list2  = {{{list2-list2}}}
<!--end-->
|below = {{{below}}}
}}

转换注意

由于{{Navbox}}系列的实现较为复杂和涉及自我嵌套,本模板的实现也为此做了对应兼容性调整,可能会出现一些参数被过度透传(可能在样式控制部分,原因是原有设计通过控制参数传入来隔离,而本设计为了使参数扁平化,导致部分这些参数无法隔离)。而且模板参数非常依赖命名规律,在转换替换前,请进行testcase检查,确认转换后能与原来的样式、功能基本一致,才应用转换。如果出现问题,请保留案例并联系本模板维护编辑协助处理,或者放弃

虽然可以在值字段(例如listcol等)重新嵌入{{Navbox}}系列模板,但这和原有做法一样,失去了本模板降低解析器限制的作用,不建议这样做。

--
-- This module implements {{NavboxV2}}
--
local p = {}

local NavboxContext = require('Module:NavboxV2/NavboxContext')
local EvenoddContext = require('Module:NavboxV2/EvenoddContext')
local getArgs -- lazily initialized
local DEBUG = false
--p.NavboxContext = NavboxContext

-- 全局性参数锚
local args

-- 常量定义 (Constant Define)
local Limit = {
	vertical = 35,
	horizontal = {col = 20, list = 10}, --原Navbox with columns为6个list,放宽至10
	vertical_collapsible = 20,
	child = 10
}

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

-- 模板名,用于参数获得的限定
local MainTemplateName = 'Template:NavboxV2'

-- Navbar存在标记
local haveNavBarMarker = false

-- 部分判断样式的参数
local listsCheck = {
	plainlist_t = {
		patterns = {
			'^plainlist$',
			'%splainlist$',
			'^plainlist%s',
			'%splainlist%s'
		},
		found = false,
		styles = 'Plainlist/styles.css'
	},
	hlist_t = {
		patterns = {
			'^hlist$',
			'%shlist$',
			'^hlist%s',
			'%shlist%s'
		},
		found = false,
		styles = 'Hlist/styles.css'
	}
}

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

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

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

function tableToString(_table)
	local outputs = {}
	if _table == nil then
		table.insert(outputs, '<nil>')
	elseif 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

function debugLog(prefix , ...)
	if not DEBUG then return end
	if #arg == 0 then
		mw.log(prefix)
	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(prefix,tostring(_v))
			end
		end
	end
end

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

---获得有效的类型
local getValidType = function(input, defVal)
	--[[ if input == 'with columns' then
		input = NavType.H
	elseif input == 'with collapsible groups' then
		input = NavType.VC
	end]]
	return (NavType.V == input or NavType.H == input or NavType.VC == input) and input or defVal
end

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

--- 前缀生成
local makePrefix = function(oldPrefix, thisLevel)
	return oldPrefix == "" and thisLevel or (oldPrefix .. '-' .. thisLevel)
end

--[[
获得参数
_prefix 只有1个参数时为直接取模板参数对应参数名值,否则是作为子Navbox体的前缀名,无结尾"-"
_argKey 作为子Navbox体的具体参数名
defVal  默认值
context Navbox层级的上下文,注入时如果存在_argKey对应参数值则取上下文的存入值
_contextKey 代替_argKey作为上下文的参数名
]]
local getArg = function(_prefix, _argKey, defVal, context, _contextKey)
	local contextKey = _contextKey or _argKey
	if context and contextKey and context[contextKey] then
		-- debugLog('getArg By Context',contextKey)
		return context[contextKey]
	else
		local prefix = _prefix ~= nil and _prefix or ""
		local key = (_argKey == nil and _prefix ~= nil) and _prefix or _argKey
		local argsKey = makePrefix(prefix, key)
		-- debugLog('getArg By InputArg',argsKey)
		return args[argsKey] or defVal
	end
end

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

local getListnumMakeKey = function(prefix)    
	prefix = mw.ustring.gsub(prefix,'(-)', '%%-')
	local middle = (prefix == "" and "" or "%-")
	local listKeyMatch , contentKeyMatch=
		'^' .. prefix .. middle .. 'list(%d+)',
		'^' .. prefix .. middle .. 'content(%d+)' 	
	return listKeyMatch .. '$' , listKeyMatch .. '%-' , contentKeyMatch .. '$' , contentKeyMatch .. '%-'
end

---获得listnum
local getListnum = function(prefix, limit, contentEqList)
	debugLog("getListnum", {['prefix'] = prefix, ['limit'] = limit})
	local listKeyMatchEnd, listKeyMatchSub, contentKeyMatchEnd, contentKeyMatchSub = getListnumMakeKey(prefix)
	local listnums = {}
	
	for k, v in pairs(args) do
		k = '' .. k
		-- debugLog("getListnum,k=",k)
		
		local listnum =
		(
			mw.ustring.match(k, listKeyMatchEnd) or
			mw.ustring.match(k, listKeyMatchSub)
		) or
		(
			contentEqList and ( -- VerticalCollapsibleTable 的 Content适配
			mw.ustring.match(k, contentKeyMatchEnd) or
			mw.ustring.match(k, contentKeyMatchSub)
			) or nil
		)
		if listnum and tonumber(listnum) <= limit then
			listnum = tonumber(listnum)
			table.insert(listnums, listnum)
		end
	end
	
	listnums = removeDump(listnums)
	table.sort(listnums)
	
	debugLog('getListnum End',{['listnums']=tableToString(listnums)})
	return listnums
end

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

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

	if _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(makePrefix(prefix,"col" .. tostring(i) .. "header" ), level + 1)
			end ]]

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

			_ = getArg(prefix, "col" .. tostring(i) .. "footer")
			--[[if checkHaveChild(prefix, "col" .. tostring(i) .. "footer") then
				p.shakeArgs(makePrefix(prefix, "col" .. tostring(i) .."footer" ), level + 1)
			end ]]
		end
	elseif _type == NavType.V then
		list_limit = Limit.vertical
	elseif _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
			p.shakeArgs(makePrefix(prefix, "list" .. tostring(i)), level + 1)
		end
		if checkHaveChild(prefix, "content" .. tostring(i)) then
			p.shakeArgs(makePrefix(prefix, "content" .. tostring(i)), level + 1)
		end
	end

	_ = getArg(prefix, "below")
end

-- 检查是否关闭展开折叠按钮
local hasCollapsibleToggle = function(context)
	local prefix = context.prefix
	local state = getArg(prefix, "state", nil, context)

	return not (state == 'off' or state == 'plain')
end

-- 检查是否使用过Navbar
local hasNavBar = function(context,pass)
	if pass then return haveNavBarMarker end

	local prefix = context.prefix
	local navbar, name =
		getArg(prefix, "navbar", nil, context),
		getArg(prefix, "name")
	local parentTitle = mw.getCurrentFrame():getParent():getTitle():gsub('/sandbox$', '')
	local titleCheck = false
	if type(MainTemplateName) == 'table' then
		for _ , v in pairs(MainTemplateName)  do
			if parentTitle == MainTemplateName then
				titleCheck = true
				break
			end
		end
	else
		titleCheck = (parentTitle == MainTemplateName)
	end	
	
	if navbar == 'off' or navbar == 'plain' or 
		((not name) and titleCheck ) then
		return false
	else    
		haveNavBarMarker = true --用来启动模版样式标记
		return true
	end
end

-- 从CSS中提取出颜色
local extractColor = function(cssstr)
	-- return nil because navbar takes its argument into mw.html which handles
	-- nil gracefully, removing the associated style attribute
	return mw.ustring.match(';' .. cssstr .. ';', '.*;%s*([Cc][Oo][Ll][Oo][Rr]%s*:%s*.-)%s*;') or nil
end

-- 检测class是否存在需要list
local has_list_class = function(args_to_check)
	debugLog('has_list_class',args_to_check)
	for _, list in pairs(listsCheck) do
		if not list.found then
			for _, arg in pairs(args_to_check) do
				for _, pattern in ipairs(list.patterns) do
					if mw.ustring.find(arg or '', pattern) then
						list.found = true
						break
					end
				end
				if list.found then break end
			end
		end
	end
end

local childEvenOddContextInject = function(childType,context,childContext)
	if getArg(childType,'evenodd','') ~= '' then
		childContext.oddevenContext = EvenoddContext.new(context,getArg)
	else
		childContext.oddevenContext = context.oddevenContext
	end
	if childType == NavType.H then
		childContext.noEvenOdd = true
	end
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", nil, context),
			getArg(prefix, "border", nil, context)
	debugLog('render TableHeader args', {
		['prefix'] = prefix,
		['state'] = state,
		['title'] = title,
		['border'] = border
	})

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

	if title and hasCollapsibleToggle(context) then
		if state == 'collapsed' then state = 'mw-collapsed' end -- mw-collapsible 对应 展开模式
		rootTable
			:addClass('mw-collapsible')
			:addClass(state or 'autocollapse')
	end

	if borderIsChild(border) 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

---创建三键导航
local function renderNavBar(titleCell, context)
	local prefix = context.prefix
	local name = getArg(prefix, "name")
	debugLog('render Navbar',{['name']=name})
	
	if hasNavBar(context) then
		local navbarFunc = require('Module:Navbar')._navbar
		titleCell
			:wikitext(navbarFunc {
				name,
				mini = 1,
				fontstyle = extractColor(
					table.concat({
						getArg(prefix, 'basestyle', nil, context) or '',
						getArg(prefix, 'titlestyle', nil, context) or ''
					}, ';')
				)
			})
	end

	debugLog('render Navbar End')
end

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

	local titleCell = titleRow:tag('th'):attr('scope', 'col')
	local titleColspan = context.totalColspan
	if hasCollapsibleToggle(context) then
		titleCell:addClass('collapsible-title')
	end

	--[[
		如果是水平式,层级大于1(作为子Navbox),border是子类型,
		有奇偶上下文的话,
		重新初始化新上下文
	]] 
	do
		local border, type = 
			getArg(prefix, "border", nil, context), getValidType(context.type, nil)
		if  type == NavType.V and 
			context.level > 1 and  
			borderIsChild(border) and 
			context.oddevenContext ~= nil 
		then
			debugLog("oddevenContext reset")
			context.evenodd = context.oddevenContext.evenodd 
			context.oddevenContext = EvenoddContext.new(context,getArg)
			context.evenodd = nil
		end
	end

	titleCell
		:cssText(basestyle)
		:cssText(getArg(prefix, "titlestyle", nil, context))
		:addClass('navbox-title')
		:attr('colspan',titleColspan)

	renderNavBar(titleCell, context)
	
	titleCell
		:tag('div')
			-- id for aria-labelledby attribute
			:attr('id', mw.uri.anchorEncode(title))
			:addClass(titleclass)
			:css('font-size', '110%')
			:css('margin', '0 5em')
			:wikitext(addNewline(title))

	debugLog('render TitleRow End')
end

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

	local title = getArg(prefix, "title", nil, context)
	local Colspan = context.totalColspan
	local AboveRow = rootTable:tag('tr')
	AboveRow
		:tag('td')
			:addClass('navbox-abovebelow')
			:addClass(aboveclass)
			:cssText(getArg(prefix, "basestyle"))
			:cssText(getArg(prefix,"abovestyle"))
			:attr('colspan', Colspan)
			:tag('div')
				-- id for aria-labelledby attribute, if no title
				:attr('id', (not title) and mw.uri.anchorEncode(above) or nil)
				:wikitext(addNewline(above))

	debugLog('render AboveRow End')
end

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

	local Colspan = context.totalColspan
	local BelowRow = rootTable:tag('tr')
	BelowRow
		:tag('td')
			:addClass('navbox-abovebelow')
			:addClass(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("FunctionInrenderColRow",
				 {['traceback']=debug.traceback(),['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)

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

	-- image
	local imageLeft, image, imageclass, insertImage =
		getArg(prefix, "imageleft", nil, context),
		getArg(prefix, "image", nil, context),
		getArg(prefix, "imageclass", 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
			has_list_class({imageclass})
			debugLog('imageLeftRow', {['imageLeft'] = imageLeft})
			listRow
				:tag('td')
					:addClass('noviewer')
					:addClass('navbox-image')
					:addClass(getArg(prefix, "imageclass", nil, context))
					:css('width', '1px') -- Minimize width
					:css('padding', '0px 2px 0px 0px')
					:cssText(imageclass)
					:attr('rowspan', ImageRowspan)
						:tag('div')
							:wikitext(addNewline(imageLeft))
						:done() -- div done
					:done() -- td done
		end
		if image then insertImage = true end
	end

	-- group start
	local needGroup, haveGroupWidth = false, false
	do 
		local group, groupclass, groupwidth =
			getArg(prefix,"group" ..listnum,nil,context),
			getArg(prefix, "groupclass", nil, context),
			nil
		if group and not notNeedGroup then needGroup = true end 
		if group then groupwidth = getArg(prefix,"groupwidth") end
		if groupwidth then haveGroupWidth = true end 
		--debugLog("_renderListRow().group_part",{['group']=group,['groupwidth']=groupwidth})
				
		if needGroup then
			has_list_class({groupclass})
			debugLog('groupTh', {['group'] = group})
			groupCell = listRow:tag('th')

			-- id for aria-labelledby attribute, if lone group with no title or above
			local title, above = getArg(prefix, "title", nil, context), getArg(prefix, "above")
			if isFirst and not (title or above or getArg(prefix, "group2", nil, context)) then
				groupCell:attr('id', mw.uri.anchorEncode(group))
			end

			groupCell
					:attr('scope', 'row')
					:addClass('navbox-group')
					:addClass(groupclass)
					:cssText(getArg(prefix, "basestyle"))
					:css('width', groupwidth or "1%" ) -- If groupwidth not specified, minimize width
					:cssText(getArg(prefix, "groupstyle"))
					:cssText(getArg(prefix,'group' ..listnum ..'style'))
					:wikitext(group)
		end
	end
	-- group end
	
	-- list start
	do
		local listHaveChild = checkHaveChild(prefix, 'list' .. listnum)
		local contentHaveChild = context.contentEqList and checkHaveChild(prefix, 'content' .. listnum)
		
		listCell = listRow:tag('td')
		if needGroup then
			listCell:addClass('navbox-list-with-group')
		else
			listCell:attr('colspan', 2)
		end

		if not haveGroupWidth then listCell:css('width', '100%') end
		
		-- list奇偶控制 start
		local evenOdd , evenOddNavBoxClass , evenOddStyle 
		if not (listHaveChild or contentHaveChild) then --有子Navbox则不生成奇偶
			if context.oddevenContext ~= nil then --基于上下文的奇偶控制
				local _evenOdd , _evenOddNavBoxClass , _evenOddStyle , _
				_evenOddStyle = (isOdd and getArg(prefix, "oddstyle", "", context)) or getArg(prefix, "evenstyle", "", context)
				if (context.noEvenOdd or false) then -- 除list外部分停止使用奇偶交替
					_evenOdd , _evenOddNavBoxClass = "odd", "navbox-odd" 
					debugLog("evenoddContext.noEvenOdd",{_evenOdd , _evenOddNavBoxClass , _evenOddStyle })
				else
					_evenOdd , _evenOddNavBoxClass = context.oddevenContext:next();
					debugLog("evenoddContext",{_evenOdd , _evenOddNavBoxClass , _evenOddStyle })
				end
				
				if context.lockEvenOdd then -- CollapsibleListRow 适配
					_evenOdd = "odd"
					_evenOddNavBoxClass = 'navbox-' .. _evenOdd
				end
				if context.noEvenOddStyle then -- CollapsibleListRow 适配
					_evenOddStyle = ""
				end
				debugLog("evenoddContext.final",{_evenOdd , _evenOddNavBoxClass , _evenOddStyle })
				evenOdd , evenOddNavBoxClass , evenOddStyle =
					_evenOdd , _evenOddNavBoxClass , _evenOddStyle
			else -- 原有基于参数的奇偶模式
				local no_evenOddStyle = false 
				evenOdd = getArg(prefix, "evenodd", "")
				if evenOdd == "off" then
					no_evenOddStyle = true
				elseif evenOdd == "odd" or evenOdd == "even" then
					--isOdd = (evenOdd == "odd")
				elseif evenOdd == "swap" then
					isOdd = not isOdd
				end
				if (context.noEvenOdd or false) then -- 除list外部分停止使用奇偶交替
					no_evenOddStyle = true
				end
				if context.lockEvenOdd then -- CollapsibleListRow 适配
					evenOdd, isOdd = 'odd', true
				end
				if context.noEvenOddStyle then -- CollapsibleListRow 适配
					no_evenOddStyle = true
				end
				evenOdd = no_evenOddStyle and "odd" or (isOdd and "odd" or "even")
				evenOddStyle = no_evenOddStyle and "" 
								or ((isOdd and getArg(prefix, "oddstyle", "", context)) or getArg(prefix, "evenstyle", "", context))
				evenOddNavBoxClass = 'navbox-' .. evenOdd
				debugLog("evenodd.old",{evenOdd , evenOddNavBoxClass , evenOddStyle })
			end
		else
			evenOdd , evenOddNavBoxClass , evenOddStyle = "odd", "navbox-odd" , ""
		end
		-- list奇偶控制 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 = (isFirst and getArg(prefix, 'list1style', '', context)) or
							getArg(prefix, 'list' .. listnum .. 'style', '')
		local liststyle = getArg(prefix, "liststyle", '', context)
		local listclass = getArg(prefix, "listclass", nil , context)
		local listNclass = getArg(prefix, "list".. listnum .."class", nil , context)
		has_list_class({listclass, listNclass})
		
		listCell
			:css('padding', '0px')
			:cssText(liststyle)
			:cssText(evenOddStyle)
			:cssText(listNstyle)
			:addClass('navbox-list')
			:addClass(evenOddNavBoxClass)
			:addClass(listclass)
			:addClass(listNclass)
			
		local tempdiv = listCell:tag('div'):css('padding', listNpadding)
		if OtherListFunction then
			debugLog('ValueRow OtherListFunction', {
				['otherListFunctionDivNotClose'] = context.otherListFunctionDivNotClose
			})
			OtherListFunction(tempdiv, context.otherListFunctionDivNotClose)
		elseif (listHaveChild or contentHaveChild) and level <= Limit.child then
			local listKeyName = contentHaveChild and 'content' or 'list'
			local childPrefix= makePrefix(prefix, listKeyName ..listnum)
			local childType = getValidType(getArg(childPrefix,'type'), NavType.V)
			local childContext = NavboxContext.new(
					childPrefix,
					level + 1,
					childType
			)
			childEvenOddContextInject(childType,context,childContext)

			debugLog('ValueRow NewChild', childContext)
			tempdiv
				:done() -- div end
				:node(p.renderNavTable(childContext))
				:tag('div'):done()
		else
			local list_str = getArg(prefix, 'list' .. listnum, '')
			local content_str = getArg(prefix, 'content' .. listnum, '') -- VerticalCollapsibleTable 的 Content适配
			if not context.contentEqList then 
				content_str = ''
			end
			debugLog('ValueRow listnum', {['listnum'] = listnum})
			tempdiv:wikitext(addNewline(table.concat({list_str,content_str})))
		end
	end
	-- list end

	if insertImage then
		has_list_class({imageclass})
		debugLog('imageRow', {['image'] = image})
		listRow
			:tag('td')
				:addClass('noviewer')
				:addClass('navbox-image')
				:addClass(imageclass)
				:css('width', '1px')  -- Minimize width
				: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, 'col1header'),
		getArg(prefix, 'col1'),
		getArg(prefix, 'col1footer')
	debugLog('ColRow Implement', {['prefix'] = prefix}, context)
	-- new table root
	rootTable = mw.html.create('table')
	rootTable
		:addClass("navbox-columns-table")
		:css('border-spacing', '0px')
		:css('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

	-- header
	if col1header then

		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')
					:css('font-weight', 'bold')
					: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,context)
					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

		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 = mw.text.trim(padding)
				test0 = mw.ustring.find(padding,'^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
			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)
			debugLog('ColRow Body', {['prefix']=prefix,['colnum']=colnum,['colkey']=colkey})
			
			if colN or colNhavechild then
				local oddevenstyle = getArg(prefix, isOdd and 'oddcolstyle' or'evencolstyle')
				local colNCell = colbodyTR
					:tag('td')
						:addClass('navbox-list')
						: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 newPrefix = makePrefix(prefix , colkey)
					local childType = getValidType(getArg(newPrefix, 'type'), NavType.H)
					local childContext = NavboxContext.new(
							newPrefix,
							level + 1,
							childType
					)
					childEvenOddContextInject(childType,context,childContext)
					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('\n'..colN..'\n'))
				end
			end
			debugLog('ColRow Body End', {['colnum'] = colnum})
		end
	end

	-- footer
	if col1footer then

		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')
					:css('font-weight', 'bold')
					: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,context)
					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'] = 1

	_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 = ''

	-- 传入本级奇偶样式
	do 
		local oddstyle , evenstyle = getArg(prefix, 'oddstyle', ''), getArg(prefix, 'evenstyle', '')
		if oddstyle ~= '' then context.oddstyle = oddstyle end
		if evenstyle ~= '' then context.evenstyle = evenstyle end
	end

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

	-- 传入renderTitleRow
	-- context.titleEqGroup=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.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 childPrefix = makePrefix(prefix , listKeyName .. listnum)
		local childContext = NavboxContext.new(
				childPrefix,
				level + 1,
				getValidType(getArg(childPrefix, 'type'),NavType.V)
		)
		childContext.oddevenContext = context.oddevenContext
		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
	local title = getArg(prefix, 'group' .. listnum, '') ..
	   getArg(prefix, 'sect' .. listnum, '' ) ..
	   getArg(prefix, 'section' .. listnum, '')
	 if title ~= '' then
		local grandChild_context = NavboxContext.new(prefix, level)
		grandChild_context.notNeedGroup = true
		grandChild_context.listpadding = getArg(prefix, 'listpadding')
		grandChild_context.listnum = listnum
		grandChild_context.listindex = context.listindex
		grandChild_context.oddevenContext = context.oddevenContext
		grandChild_context.title = title
		context_function = _renderColRow_FunctionBuilder(
							rootTable,
							grandChild_context,
							_renderSmallNavboxInCollapsibleListRow)
		debugLog('renderCollapsibleListRow function generate', {
			['context'] = context,
			['grandChild_context'] = grandChild_context
		})
	end
	
	context.noEvenOddStyle = true
	context.contentEqList = true
	debugLog('renderCollapsibleListRow renderListRow', {['context'] = context})
	_renderListRow(rootTable, context, context_function)
	context.noEvenOddStyle = nil
	context.contentEqList = nil
	debugLog('renderCollapsibleListRow End')
end

---------------------------------------------------------------
--
--   Tracking categories
--

-- 没有使用水平列表的导航框
local function needsHorizontalLists(context)
	local prefix = context.prefix
	local border, tracking  =
				context.border or getArg(prefix, 'border'),
				getArg(prefix, 'tracking')
	debugLog('needsHorizontalLists',
		{['border']=border,['tracking']=tracking})
	if borderIsChild(border) or tracking == 'no' then
		return false
	end

	return not listsCheck.hlist_t.found and not listsCheck.plainlist_t.found
end

-- 使用背景颜色的导航框
local function hasBackgroundColors(context)
	local prefix = context.prefix
	for _, key in ipairs({'titlestyle', 'groupstyle', 'basestyle'}) do
		local style=context[key] or getArg(prefix, key) or ''
		if tostring(style):find('background', 1, true) then
			return true
		end
	end
	return false
end

-- name參數和實際不同的導航框
local function argNameAndRealTitleAreDifferent(context)
	local prefix = context.prefix
	local border, name, tracking =
				getArg(prefix, 'border', nil, context),
				getArg(prefix, 'name', nil, context),
				getArg(prefix, 'tracking')
	debugLog('argNameAndRealTitleAreDifferent',
		{['border']=border,['name']=name,['tracking']=tracking})
	if borderIsChild(border) or tracking == 'no' or not hasNavBar(context) then
		return false
	end

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

local catCheckList = {
	['needsHorizontalLists'] = {
		['catkey'] = 'needsHorizontalLists',
		['catCheckFunc'] = needsHorizontalLists,
		['catName'] = '没有使用水平列表的导航框'
	},
	['hasBackgroundColors'] = {
		['catkey'] = 'hasBackgroundColors',
		['catCheckFunc'] = hasBackgroundColors,
		['catName'] = '使用背景颜色的导航框'
	},
	--[[
	['argNameAndRealTitleAreDifferent'] = {
		['catkey'] = 'argNameAndRealTitleAreDifferent',
		['catCheckFunc'] = argNameAndRealTitleAreDifferent,
		['catName'] = 'name參數和實際不同的導航框'
	}
	]]
}

-- 检查并获得需要的分类
local function getTrackingCategories(context)
	local cats = _G['globalCatList'] or {}
	for catkey, checkObj in pairs(catCheckList) do
		if checkObj['catCheckFunc'](context) then
			table.insert(cats, checkObj['catkey'])
		end
	end
	debugLog('getTrackingCategories',{['level']=context.level,['catList']=cats})
	_G['globalCatList'] = cats
end

-- 生成分类
local function renderTrackingCategories(builder, context)
	local title = mw.title.getCurrentTitle()
	if DEBUG == false then
		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 --
	end

	getTrackingCategories(context)
	debugLog('renderTrackingCategories',{['level']=context.level})
	
	if context.level ==1 then
		local catList=_G['globalCatList'] or {}
		catList = removeDump(catList)
		for i, cat in ipairs(catList) do
			builder:wikitext('[[Category:' .. catCheckList[cat]['catName'] ..']]')
		end
	end
end
---------------------------------------------------------------
--
-- 模板样式的调整
--

-- work around [[phab:T303378]]
-- for each arg: find all the templatestyles strip markers, insert them into a
-- table. then remove all templatestyles markers from the arg
local function move_hiding_templatestyles(args)
	local gfind = string.gfind
	local gsub = string.gsub
	local templatestyles_markers = {}
	local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
	for k, arg in pairs(args) do
		for marker in gfind(arg, strip_marker_pattern) do
			table.insert(templatestyles_markers, marker)
		end
		args[k] = gsub(arg, strip_marker_pattern, '')
	end
	return templatestyles_markers
end

--
-- Load the templatestyles for the navbox
--
local function loadTemplateStyles(hiding_templatestyles)
	local frame = mw.getCurrentFrame()
	local templateStyles = {}

	-- 提前注入,到时清空
	templateStyles[1] = frame:extensionTag{
		name = 'templatestyles', args = { src = listsCheck.hlist_t.styles }
	}
	templateStyles[2] = frame:extensionTag{
		name = 'templatestyles', args = { src = listsCheck.plainlist_t.styles }
	}
	--[[
	if listsCheck.hlist_t.found then
		hlist_templatestyles = frame:extensionTag{
			name = 'templatestyles', args = { src = listsCheck.hlist_t.styles }
		}
	else
		templateStyles[1] = ''
	end
	]]
	--[[
	-- a second workaround for phab:T303378
	-- when that issue is fixed, we can actually use has_navbar not to emit the
	-- tag here if we want]]
	--[[
	if hasNavBar(nil,true) and hlist_templatestyles == '' then
		hlist_templatestyles = frame:extensionTag{
			name = 'templatestyles', args = { src = listsCheck.hlist_t.styles }
		}
		templateStyles[1] = hlist_templatestyles
	end]]
	--[[
	if listsCheck.plainlist_t.found then
		 templateStyles[2] = frame:extensionTag{
			name = 'templatestyles', args = { src = listsCheck.plainlist_t.styles }
		}
	else
		templateStyles[2] = ''	
	end
	]]

	templateStyles[3] = frame:extensionTag{
		name = 'templatestyles', args = { src = 'Module:Navbox/styles.css' }
	}

	local base_templatestyles = getArg("","templatestyles","")
	if base_templatestyles~= '' then
		templateStyles[4] = frame:extensionTag{
			name = 'templatestyles', args = { src = base_templatestyles }
		}
	else
		templateStyles[4] = ''
	end

	local child_templatestyles = getArg("","child templatestyles","")
	if child_templatestyles~= '' then 
		templateStyles[5] = frame:extensionTag{
			name = 'templatestyles', args = { src = child_templatestyles }
		}
	else
		templateStyles[5] = ''
	end
	
	-- 其他
	for _ , v in pairs(hiding_templatestyles) do
		templateStyles[#templateStyles+1] = v
	end
	
	return templateStyles
end

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

---水平式 (col)
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

	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
	else
		debugLog('render Horizontal NavTable,have list with col', {listnums})
		if getArg(prefix, "evenOdd", "") == "" and context.oddevenContext == nil then 
			context.oddevenContext = EvenoddContext.new(context,getArg)
		end
		for i, listnum in ipairs(listnums) do
			context.listnum = listnum
			if listnum == 1 then
				-- 一行Col

				context.noEvenOdd = true
				renderColRow(rootTable, context)
				context.notNeedImage = true

				-- clear
				context.noEvenOdd = nil
			else
				context.notNeedImage = nil
			end
			context.listindex = i
			_renderListRow(rootTable, context)
		end
	end
	renderBelowRow(rootTable, context)

	if (getArg("nocat") or 'false'):lower() == 'false' then
	   renderTrackingCategories(rootTable, context)
	end
	debugLog('render Horizontal NavTable End')
	return rootTable
end

---垂直式 (list)
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

	renderTitleRow(rootTable, context)
	renderAboveRow(rootTable, context)
	
	if getArg(prefix, "evenOdd", "") == "" and context.oddevenContext == nil then 
		context.oddevenContext = EvenoddContext.new(context,getArg)
	end
	for i, listnum in ipairs(listnums) do
		context.listnum = listnum
		context.listindex = i
		renderListRow(rootTable, context)
	end
	renderBelowRow(rootTable, context)

	if (getArg("nocat") or 'false'):lower() == 'false' then
	   renderTrackingCategories(rootTable, context)
	end
	debugLog('render Vertical NavTable End')
	return rootTable
end

---垂直折叠式(Collapsible, list/content )
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

	renderTitleRow(rootTable, context)
	renderAboveRow(rootTable, context)
	if getArg(prefix, "evenOdd", "") == "" and context.oddevenContext == nil then 
		context.oddevenContext = EvenoddContext.new(context,getArg)
	end
	for i, listnum in ipairs(listnums) do
		context.listnum = listnum
		context.listindex = i
		renderCollapsibleListRow(rootTable, context)
	end
	renderBelowRow(rootTable, context)

	if (getArg("nocat") or 'false'):lower() == 'false' then
	   renderTrackingCategories(rootTable, context)
	end
	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(templateArgs, context)
	args = templateArgs -- 转移模板入参
	debugLog('Navbox mainfuntion', context)
	local prefix, level = context.prefix, context.level
	local navboxclass, title, above, group1, group2 =
		getArg(prefix, "navboxclass"),
		getArg(prefix, "title", nil, context),
		getArg(prefix, "above"),
		getArg(prefix, "group1", nil, context),
		getArg(prefix, "group2", nil, context)
	local hiding_templatestyles = move_hiding_templatestyles(args)
	
	local rootTable
	--[[
	适配list内再嵌套单独Navbox的情况,部分Navbox可以单独或者再嵌入使用
	原生的Navbox的各种实现机制就是Navbox嵌套
	]]
	local border = mw.text.trim(getArg(prefix, 'border') or getArg(prefix, '1') or '')
	debugLog("_Navbox.border", border)
	local templateStylesArr={}
	if border == 'none' then
		templateStylesArr=loadTemplateStyles(hiding_templatestyles)
		rootTable = mw.html.create('div')
		rootTable
			:attr('role', 'navigation')
			:node(p.renderNavTable(context):allDone())
		-- aria-labelledby title, otherwise above, otherwise lone group
		if title or above or (group1 and not group2) then
			rootTable:attr('aria-labelledby', mw.uri.anchorEncode(title or above or group1))
		else
			rootTable:attr('aria-label', 'Navbox')
		end
		if not (listsCheck.hlist_t.found or hasNavBar(nil,true)) then
			templateStylesArr[1] = "" --清空掉
		end
		if not listsCheck.plainlist_t.found then
			templateStylesArr[2] = "" --清空掉
		end
	elseif borderIsChild(border) then
		-- Navbox的值段直接嵌套单独Navbox的情况
		rootTable = mw.html.create()
		rootTable
			:wikitext('</div>')
			:node(p.renderNavTable(context):allDone())
			:wikitext('<div>')
	else
		templateStylesArr=loadTemplateStyles(hiding_templatestyles)
		has_list_class({navboxclass})
		rootTable = mw.html.create('div')
		rootTable
			:attr('role', 'navigation')
			:addClass('navbox')
			:addClass(navboxclass)
			:cssText(getArg(prefix, 'bodystyle'))
			:cssText(getArg(prefix, 'style'))
			:css('padding', '3px')
			:node(p.renderNavTable(context):allDone())
		-- aria-labelledby title, otherwise above, otherwise lone group
		if title or above or (group1 and not group2) then
			rootTable:attr('aria-labelledby', mw.uri.anchorEncode(title or above or group1))
		else
			rootTable:attr('aria-label', 'Navbox')
		end
		if not (listsCheck.hlist_t.found or hasNavBar(nil,true)) then
			templateStylesArr[1] = "" --清空掉
		end
		if not listsCheck.plainlist_t.found then
			templateStylesArr[2] = "" --清空掉
		end
	end
	
	local tsNode = mw.html.create('div')
		:addClass("navbox-styles")
		:wikitext(table.concat(templateStylesArr))
	debugLog('Navbox mainfuntion End')
	return tsNode:allDone() , rootTable:allDone()
end

-- Level 0 enter function
function p._L0navbox(templateArgs,moduleArgsType)
	args = templateArgs -- 转移模板入参
	local prefix, level = "", 1
	local navType = getValidType(
				getArg(prefix, 'type') or moduleArgsType, NavType.V)
	-- 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)
	return p._navbox(templateArgs,L0Context)
end

-- template enter function
function p.navbox(frame)
	if not getArgs then getArgs = require('Module:Arguments').getArgs end

	local moduleArgs = getArgs(frame, {frameOnly = true})
	DEBUG = (moduleArgs['DEBUG']=='true') or DEBUG
	MainTemplateName = moduleArgs['MainTemplateName'] or MainTemplateName
	if mw.ustring.find(MainTemplateName,",") then
		MainTemplateName = mw.text.split(MainTemplateName,",")
	end
	local templateArgs = getArgs(frame, {wrappers = MainTemplateName, trim = true})
	DEBUG = (templateArgs['DEBUG']=='true') or DEBUG
	
	debugLog('Navbox start')
	local tsNode , rootNode = p._L0navbox(templateArgs,moduleArgs['type'])
	debugLog('rootnode build done, Navbox end')
	
	return table.concat({tostring(tsNode) , tostring(rootNode)})
end

return p