模組:NavboxV2
外观
此模块被引用於約32,000個頁面。 為了避免造成大規模的影響,所有對此模块的編輯應先於沙盒或測試樣例上測試。 測試後無誤的版本可以一次性地加入此模块中,但是修改前請務必於討論頁發起討論。 模板引用數量會自動更新。 |
此模板不能在维基百科的移动视图中显示,只能在桌面版显示。请阅读文档以获得解释。 |
此模块使用Lua语言: |
本模块使用以下模板样式: |
这是{{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}}系列模板基本兼容。但新增部分参数填入:
type
:Navbox的类型,对应值为vertical
(对应{{Navbox}})、horizontal
(对应{{Navbox with columns}})、vertical_collapsible
(对应{{Navbox with collapsible groups}}),默认值为vertical
。border
:Navbox的隐藏参数,用于控制Navbox的边框机制,来使子Navbox能被嵌入到父Navbox的值字段(例如list
、col
等)中,实际对应{{Navbox subgroup}}或{{Navbox|child}}的实现机制。对应值为child
、subgroup
任一个。
- 在本模板添加子Navbox层时,必须传入这两个参数,这是本模板区分是否存在子Navbox层的依赖。本模板首层Navbox层无需添加
border
,按需添加type
。
- 在本模板添加子Navbox层时,必须传入这两个参数,这是本模板区分是否存在子Navbox层的依赖。本模板首层Navbox层无需添加
removeGroupPadding
:用于区别{{Navbox|child}}和{{Navbox subgroup}},后者在Groupn字段的单元格增加一组padding的配置,适用于子Navbox层。任意值,存在则可,为移除该padding配置(对应{{Navbox|child}})。- {{Navbox subgroup}}是{{Navbox generic}}改型为{{Navbox}}后的遗漏产物,在此变更后等效于{{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检查,确认转换后能与原来的样式、功能基本一致,才应用转换。如果出现问题,请保留案例并联系本模板维护编辑协助处理,或者放弃。
虽然可以在值字段(例如list
、col
等)重新嵌入{{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(imageclass)
:css('width', '1px') -- Minimize width
: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
-- 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(' ')
: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 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