Module:Sandbox/サンムル/Nav
简介
本模块为优化分析器展开模板过程中耗费的各项资源,仅针对{{Navbar}}、{{Navbox}}及其姊妹模板,在以下版本的基础上翻译改写而成,部分模板在翻译改写过程中按照使用者习惯等因素对参数有部分增删,细则请见#参数增删。
开发相关
本节将整理介绍模块代码中使用的各个函数的功能、参数及返回值,以便未来维护所需。
外部调用
模块的导出函数之一,在Wiki代码中通过{{#invoke:Nav|bar}}
调用,用于构建模板{{Navbar}}的Wiki代码。
模块的导出函数之一,在Wiki代码中通过{{#invoke:Nav|box}}
调用,用于构建模板{{Navbox}}及其姊妹模板的Wiki代码。
内部调用
notnil
notnil( value, default )
本函数检查value
是否为空值,如果是则返回default
,否则返回value
。
__nn
是本函数的别名。
notnilnorempty
notnilnorempty( value, default )
本函数检查value
是否为空值或零长度字符串,如果是则返回default
,否则返回value
。
__nne
是本函数的别名。
notnilnorwhitespace
notnilnorwhitespace ( value, default )
本函数检查value
是否为空值或空白字符组成的字符串,如果是则返回default
,否则返回value
。
__nnw
是本函数的别名。
notnilnoremptynorwhitespace
notnilnoremptynorwhitespace ( value, default )
本函数检查value
是否为空值、零长度字符串或空白字符组成的字符串,如果是则返回default
,否则返回value
。
__nnew
是本函数的别名。
iif
iif( condition, truevalue, falsevalue )
本函数检查condition
的值,若为真时返回truevalue
,否则返回falsevalue
。
等同于以下代码:
if condition then return truevalue else return falsevalue end
paramindexes
paramindexes( paramname, pattern )
本函数用于获取参数名称paramname
中的序号部分,例如list18
中的18
。
pattern
的格式以正则表达式为基础,因此其格式应当遵守Unicode字符串匹配的模式。在前者基础上有以下规则:
%
:将自动替换成正则表达式的(%d+)
,用以匹配这个位置上的序号;%%
:将自动替换成正则表达式的%
,用作正则表达式中%
字符的转义。
函数返回结果格式为:【所有序号文本】 【所有序号数值】
,其中每个值段都是一个独立的返回值列表项。
若格式错误,则返回nil
。
示例:
local paramname = "prefix000infix10postfix08" local pattern = "^prefix%infix%postfix%$" print( paramindexes( paramname, pattern ) ) -- 打印结果: -- 000 10 08 0 10 8
indexedparamvalue
indexedparamvalue( args, pattern, raw, index, rawfunc, indexfunc )
本函数用于获取参数表中指定序号的参数名称对应的参数值。
args:参数表; pattern:构造参数名称时遵循的模式,追加以下规则:
%
:将自动替换成raw
或index
的对应位置的序号;%%
:将自动替换成%
,用作%
字符的转义。
raw、index:分别表示序号文本和序号数值。
rawfunc、indexfunc:分别表示使用序号文本和序号数值构造参数名称后,从参数表中取得对应参数值的处理函数。
- 当
rawfunc
不为nil
且indexfunc
为nil
时,indexfunc
将使用rawfunc
的值。或者可以理解为,使用同一个函数处理两个参数值; - 其他情况下,两个参数的默认值均为
notnilnoremptynorwhitespace
。
若遇到名称形如list18
、list018
、list0000018
等序号数值同为18
的参数共存的情况下,本函数按照以下顺序获取参数值:
- 查找使用序号文本即
raw
参数构造的参数名称; - 查找使用序号数值即
index
参数构造的参数名称; - 遍历参数表
args
中所有符合格式pattern
且序号一致的参数,顺次对每个参数先后使用rawfunc
和indexfunc
处理,返回第一个不为nil
的值。- 顺次可能并不与调用页面的Wiki代码中参数表的书写顺序一致,其顺序依循各Lua解释器的内部实现。
local nav = {} local notnil = function(value, default) return value or default end local __nn = notnil local notnilnorempty = function(value, default) if value == nil then return default elseif type(value) == "string" and value == "" then return default else return value end end local __nne = notnilnorempty local notnilnorwhitespace = function(value, default) if value == nil then return default elseif type(value) == "string" then if value == "" then return value elseif mw.text.trim(value) == "" then return default else return value end else return value end end local __nnw = notnilnorwhitespace local notnilnoremptynorwhitespace = function(value, default) if value == nil then return default elseif type(value) == "string" and mw.text.trim(value) == "" then return default else return value end end local __nnew = notnilnoremptynorwhitespace local iif = function(condition, truevalue, falsevalue) if condition then return truevalue else return falsevalue end end --[[ 获取当前参数的序号,支持多个序号,且支持多种写法兼容。 pattern: 格式以正则表达式为基础,另增以下匹配符: % - 将自动替换成正则表达式的“(%d+)”,用以匹配这个位置上的序号。 %% - 将自动替换成正则表达式的“%”,用作正则表达式中“%”字符的转义。 返回: 【所有序号文本】 【所有序号数值】 注:以上每个值段都是一个独立的返回值列表项; 示例: paramname: prefix000infix10postfix08 pattern: ^prefix%infix%postfix%$ 返回:000 10 08 0 10 8 --]] local paramindexes = function(paramname, pattern) local indexes = { mw.ustring.match(paramname, mw.ustring.gsub(pattern, "%%%%?", function(m) if m == "%%" then return "%" else return "(%d+)" end end)) } local count = #indexes if count ~= 0 then for i = 1, count do indexes[i + count] = tonumber(indexes[i]) end return unpack(indexes) end end local indexedparamvalue = function(args, pattern, raw, index, rawfunc, indexfunc) if args == nil or pattern == nil or raw == nil or index == nil then return nil end if rawfunc ~= nil and indexfunc == nil then indexfunc = rawfunc end rawfunc = rawfunc or __nnew indexfunc = indexfunc or __nnew if type(raw) ~= "table" then raw = { raw } end if type(index) ~= "table" then index = { index } end local i = 0 rawname = mw.ustring.gsub(pattern, "%%%%?", function(m) if m == "%%" then return "%" else i = i + 1 return tostring(raw[i] or "") end end) rawvalue = args[rawname] local result = rawfunc(rawvalue) if result then return result end i = 0 indexname = mw.ustring.gsub(pattern, "%%%%?", function(m) if m == "%%" then return "%" else i = i + 1 return tostring(index[i] or "") end end) indexvalue = args[indexname] result = indexfunc(indexvalue) if result then return result end local fuzzyMatchingOn = __nnew(args.fuzzyMatchingOn, "no") == "yes" -- 模糊匹配。 if not fuzzyMatchingOn then return nil end -- 不启用参数名模糊匹配时处理流程到此结束。 -- 开始进行参数名模糊匹配。 -- 由于大多数参数名格式均为“【名称】【数字序号】”,将【名称】前缀作为第一道筛选程序将会减少耗时的正则匹配函数运行次数,大大优化代码运行效率。 local prefixpos = 1 local v1, v2 = 1, 0 while true do local v1, v2 = mw.ustring.find(pattern, "%%+", v1) if v1 == nil then prefixpos = mw.ustring.len(pattern) + 1 break elseif (v2 - v1) % 2 == 0 then prefixpos = v2 break else v1 = v2 + 1 end end local prefix = mw.ustring.gsub(mw.ustring.sub(pattern, 1, prefixpos - 1), "%%%%", "%") -- 获取纯文本前缀。 local prefixlen = mw.ustring.len(prefix) -- 获取纯文本前缀字符长度。 for k, v in pairs(args) do if k ~= rawname and k ~= indexname and mw.ustring.sub(k, 1, prefixlen) == prefix then -- 排除已处理参数名称,并筛选【名称】前缀。 local indexes = { paramindexes(k, "^"..pattern.."$") } -- 获取各序号部分。 local offset = #indexes / 2 -- 纯数字序号部分的偏移值,也作为序号的个数。 if #index == offset then -- 序号数量一致。 local equal = true -- 序号序列一致标识符。 for _i, _index in ipairs(index) do if _index ~= indexes[_i + offset] then equal = false break end end if equal then result = rawfunc(v) or indexfunc(v) if result then return result end end end end end end local xor = function(left, right) return (left == true and right ~= true) or (left ~= true and right == true) end local detectevenodd = function(list_previous, evenodd_i, evenodd, iseven) if evenodd_i == "swap" then if evenodd == "even" or evenodd == "odd" then return true, evenodd -- 每次swap都交换一次,基础值:全局evenodd。 else return true, nil -- 每次swap都交换一次。 end end if evenodd == "even" or evenodd == "odd" then return false, evenodd -- 不交换,基础值:全局evenodd。 end if list_previous then -- 在上一个列表的HTML代码中查找最后一项的class。 list_previous = mw.ustring.gsub(list_previous, "<!%-%-.-%-%->", "") -- 删除HTML注释。 local evenodd_previous = nil -- 上一个navbox-list奇偶样式(抓取自td标签的class属性)。 for tagstart, classstr in mw.ustring.gmatch(list_previous, [[<%s*([Tt][Dd][^>]-)%s[Cc][Ll][Aa][Ss][Ss]="([^"]-navbox%-list[^"]-)"]]) do if mw.text.trim(mw.ustring.sub(tagstart, 3, 3)) == "" then -- 标签是td。 for _, class in ipairs(mw.text.split(classstr, "%s+")) do class = mw.ustring.match(class, "^navbox%-(.+)$") if class == "even" or class == "odd" then evenodd_previous = class end end end end if evenodd_previous then -- 找到上一个列表中的最后一项的class return xor(evenodd_previous == "even", not iseven), nil -- 当最后一项的奇偶性与当前项的奇偶性相同时交换一次。 end end return false, nil -- 不进行样式修正。 end local function _bar(args, frame) local node = mw.html.create() local nodiv = __nnew(args.nodiv) local style = __nnew(args.style) if nodiv then node = node:wikitext(" "):tag("span") else node = node:tag("div") end node:addClass("noprint") :addClass("plainlinks") :addClass("hlist") :addClass("navbar") :addClass("nomobile") :cssText(style) ---------------核心代码--------------- --- 左方括号 --- local brackets = __nnew(args.brackets) if brackets then node = node:wikitext("[") end --- 前文 --- local mini = __nnew(args.mini) local miniv = __nnew(args.miniv) local plain = __nnew(args.plain) or __nnew(args.viewplain) if not (mini or miniv or plain) then node:wikitext("本模板: ") end local _1 = __nn(args[1], "{{{1}}}") local fontstyle = __nnew(args.fontstyle) local fontcolor = __nnew(args.fontcolor, "#002bb8") local history = __nnew(args.history) local purge = __nnew(args.purge) local span node:wikitext("[[Template:".._1.."|") span = node:tag("span") :css("background", "transparent!important") if fontstyle then span:cssText(fontstyle) else span:css("color", fontcolor) end span:attr("title", frame:expandTemplate{ title = "lan", args = { ["zh-hans"] = "查看这个模板", ["zh-hant"] = "檢視這個模板" }} ) if miniv then span:wikitext("v") elseif plain then span:wikitext("view") elseif mini then span:wikitext("查") else span:wikitext(frame:expandTemplate{ title = "lan", args = { ["zh-hans"] = "查看", ["zh-hant"] = "檢視" }}) end node:wikitext("]]") if not (miniv or plain) then node:wikitext(" • [[Template talk:".._1.."|") span = node:tag("span") :css("background", "transparent!important") if fontstyle then span:cssText(fontstyle) else span:css("color", fontcolor) end span:attr("title", frame:expandTemplate{ title = "lan", args = { ["zh-hans"] = "关于这个模板的讨论页面", ["zh-hant"] = "關於這個模板的討論頁面" }} ) if mini then span:wikitext("论") else span:wikitext("讨论") end node:wikitext("]] • [") :wikitext(frame:preprocess("{{fullurl:Template:".._1.."|action=edit}}")) :wikitext(" ") span = node:tag("span") :css("background", "transparent!important") if fontstyle then span:cssText(fontstyle) else span:css("color", fontcolor) end span:attr("title", frame:expandTemplate{ title = "lan", args = { ["zh-hans"] = "您可以编辑这个模板。请在储存变更之前先预览", ["zh-hant"] = "您可以編輯這個模板。請在儲存變更之前先預覽" }} ) if mini then span:wikitext("编") else span:wikitext("编辑") end node:wikitext("]") if history then node:wikitext(" • [") :wikitext(frame:preprocess("{{fullurl:Template:".._1.."|action=history}}")) :wikitext(" ") span = node:tag("span") :css("background", "transparent!important") if fontstyle then span:cssText(fontstyle) else span:css("color", fontcolor) end span:attr("title", frame:expandTemplate{ title = "lan", args = { ["zh-hans"] = "查看这个模板的编辑历史", ["zh-hant"] = "查詢這個模板的編輯歷史" }} ) if mini then span:wikitext("历") else span:wikitext("历史") end node:wikitext("]") end if purge then node:wikitext(" • [") :wikitext(frame:preprocess("{{fullurl:Template:".._1.."|action=purge}}")) :wikitext(" ") span = node:tag("span") :css("background", "transparent!important") if fontstyle then span:cssText(fontstyle) else span:css("color", fontcolor) end span:attr("title", frame:expandTemplate{ title = "lan", args = { ["zh-hans"] = "清除这个模板的缓存", ["zh-hant"] = "清除這個模板的緩存" }} ) if mini then span:wikitext("清") else span:wikitext("清除缓存") end node:wikitext("]") end end --- 右方括号 --- if brackets then node = node:wikitext("]"):done() end -------------------------------------- if nodiv then node:wikitext(" ") end return node end local function _box(args, frame) local node = mw.html.create() local border = __nnew(args.border) or __nne(args[1]) if border ~= nil then border = mw.text.trim(border) end -- 删去可能会有的多余的空白字符。 if type(border) == "string" then border = mw.text.trim(border) end if border == "subgroup" or border == "child" then node:wikitext("</div>") elseif border ~= "none" then node = node:tag("table") :addClass("navbox") :addClass(__nnew(args.class)) :attr("cellspacing", 0) :cssText(__nnew(args.bodystyle)) :cssText(__nnew(args.style)) :tag("tr") :tag("td") :css("padding", "2px") end node = node:tag("table") :attr("cellspacing", 0) :addClass("nowraplinks") :css("display", "table") :css("width", "100%") :cssText(__nnew(args.innerstyle)) local title = __nnew(args.title) local state = __nnew(args.state) if title then if state ~= "plain" and state ~= "off" then node:addClass("mw-collapsible") :addClass(state or "autocollapse") end end if border == "subgroup" or border == "child" or border == "none" then node:addClass("navbox-subgroup") :cssText(__nnew(args.bodystyle)) :cssText(__nnew(args.style)) else node:css("background", "transparent") :css("color", "inherit") end ---------------核心代码--------------- local imageleft = __nnew(args.imageleft) local image = __nnew(args.image) --- Title and Navbar --- local groupstyle = __nnew(args.groupstyle) local basestyle = __nnew(args.basestyle) if title then local temp = node node = node:tag("tr") local titlegroup = __nnew(args.titlegroup) if titlegroup then node = node:tag("td") :addClass("navbox-group") :cssText(basestyle) :cssText(groupstyle) :cssText(__nnew(args.titlegroupstyle)) :wikitext(titlegroup) :tag("th") :css("border-left", "2px solid #fdfdfd") :css("width", "100%") else node = node:tag("th") end local titlestyle = __nnew(args.titlestyle) node:cssText(basestyle) :cssText(titlestyle) :attr("colspan", 2 + iif(imageleft, 1, 0) + iif(image, 1, 0) + iif(titlegroup, -1, 0)) :addClass("navbox-title") local navbar = __nnew(args.navbar) local name = __nnew(args.name) if (navbar == "plain" or navbar == "off") or (not name and (border == "subgroup" or border == "child" or border == "none")) then if navbar == "off" then if state == "plain" then node:tag("div") :css("float", "right") :css("width", "6em") :wikitext(" ") end elseif state ~= "plain" then node:tag("div") :css("float", "left") :css("width", "6em") :css("text-align", 'left') :wikitext(" ") end else node:tag("div") :css("float", "left") :css("width", "6em") :css("text-align", 'left') :node(_bar({ [1] = args.name, fontstyle = iif(basestyle, (basestyle or "")..";", "")..iif(titlestyle, (titlestyle or "")..";", "").."border:none", mini = 1 }, frame)) if state == "plain" then node:tag("div") :css("float", "right") :css("width", "6em") :wikitext(" ") end end node:tag("span") :css("font-size", iif(border == "subgroup" or border == "child" or border == "none", "100%", "110%")) :wikitext(args.title or "{{{title}}}") node = temp -- 复原节点位置 end --- Above --- local above = __nnew(args.above) if above then if title then node:tag("tr"):css("height", "2px"):tag("td") end node:tag("tr"):tag("td") :addClass("navbox-abovebelow") :cssText(basestyle) :cssText(__nnew(args.abovestyle)) :attr("colspan", 2 + iif(imageleft, 1, 0) + iif(image, 1, 0)) :wikitext(args.above or "{{{above}}}") end --- Body --- local lists = {} local listmax = 0 for k, v in pairs(args) do if type(k) == "string" and mw.ustring.sub(k, 1, 4) == "list" then local raw, index = paramindexes(k, "^list%$") if index ~= nil and index > 0 and __nnew(v) then table.insert(lists, { raw, index, v }) -- 添加新项 lists[tostring(index)] = #lists -- 将字符串格式的搜索键映射到对应的新项索引 listmax = math.max(listmax, index) end end end --- groups/lists --- local evenstyle = __nnew(args.evenstyle) local oddstyle = __nnew(args.oddstyle) local evenodd = __nnew(args.evenodd) local liststyle = __nnew(args.liststyle) local listpadding = __nnew(args.listpadding) local visiblelist = 0 -- 可见的列表。 local imageleftnode, imagenode local swap = evenodd == "swap" -- 列表项奇偶样式是否交换。 local autoSwapOn = __nnew(args.autoSwapOn, "yes") == "yes" -- 自动交换开关。 for index = 1, listmax do if lists[tostring(index)] then -- 存在这个键 visiblelist = visiblelist + 1 -- 增加计数。 local raw, _, list_i = unpack(lists[lists[tostring(index)]]) if visiblelist > 1 or (title or above) then node:tag("tr"):css("height", "2px"):tag("td") end local tr = node:tag("tr") if visiblelist == 1 then if imageleft then imageleftnode = tr:tag("td") :css("width", "0%") :css("padding", "0px 2px 0px 0px") :cssText(__nnew(args.imageleftstyle)) :wikitext(imageleft) end end local td local group_i = indexedparamvalue(args, "group%", raw, index) if group_i then local groupstyle_i = indexedparamvalue(args, "group%style", raw, index) td = tr:tag("td") :addClass("navbox-group") :cssText(basestyle) :cssText(groupstyle) :cssText(groupstyle_i) :wikitext(group_i) :done() :tag("td") :css("text-align", "left") :css("border-left", "2px solid #fdfdfd") else td = tr:tag("td") :attr("colspan", 2) end local liststyle_i = indexedparamvalue(args, "list%style", raw, index) local list_previous = nil -- 上一个可见列表内容。 if autoSwapOn then -- 通过控制list_previous是否为nil来控制是否执行自动交换程序。 for _index = index - 1, 1, -1 do if lists[tostring(_index)] then -- 存在这个键 _, _, list_previous = unpack(lists[lists[tostring(_index)]]) break end end end local evenodd_i = indexedparamvalue(args, "evenodd%", raw, index) if evenodd_i ~= "even" and evenodd_i ~= "odd" then local swap_i = nil swap_i, evenodd_i = detectevenodd(list_previous, evenodd_i, evenodd, xor(visiblelist % 2 == 0, swap)) -- 查找上一列表中的最后一项的样式。 if swap_i == "error" then error(tostring(visiblelist)..","..tostring(swap)) end if swap_i then swap = not swap end -- 交换列表项奇偶样式。 if evenodd_i then if swap then evenodd_i = iif(evenodd_i == "even", "odd", "even") end else evenodd_i = iif(xor(visiblelist % 2 == 0, swap), "even", "odd") end end td:css("width", "100%") :css("padding", "0px") :cssText(liststyle) :cssText(liststyle_i) :addClass("navbox-list") :addClass("navbox-"..evenodd_i) :tag("div") :css("padding", listpadding or "0em 0.25em") :wikitext(list_i) if evenodd_i == "even" then td:cssText(evenstyle) elseif evenodd_i == "odd" then td:cssText(oddstyle) else td:cssText(iif(xor(visiblelist % 2 == 0, swap), evenstyle, oddstyle)) -- 偶数行使用evenstyle,奇数行使用oddstyle。(特殊情况下交换。) end if visiblelist == 1 then if image then imagenode = tr:tag("td") :css("width", "0%") :css("padding", "0px 0px 0px 2px") :cssText(__nnew(args.imagestyle)) :wikitext(image) end end end end if imageleftnode then imageleftnode:attr("rowspan", visiblelist * 2 - 1) end if imagenode then imagenode:attr("rowspan", visiblelist * 2 - 1) end --- Below --- local below = __nnew(args.below) if below then if title or above or visiblelist ~= 0 then node:tag("tr"):css("height", "2px"):tag("td") end node:tag("tr"):tag("td") :addClass("navbox-abovebelow") :cssText(basestyle) :cssText(__nnew(args.belowstyle)) :attr("colspan", 2 + iif(imageleft, 1, 0) + iif(image, 1, 0)) :wikitext(below) end -------------------------------------- node = node:allDone() -- 回到最上层节点。 if border == "subgroup" or border == "child" then node:wikitext("<div>") end return node end local function _subgroupbox(args, frame) args.border = "subgroup" args.style = "display:table;"..(args.style or "")..(args.bodystyle or "") args.groupstyle = "padding-left:0em;padding-right:0em;"..(args.groupstyle or "") local grouppadding = __nnew(args.grouppadding) for k, v in pairs(args) do if type(k) == "string" and mw.ustring.sub(k, 1, 4) == "list" then local raw, index = paramindexes(k, "^list%$") if index ~= nil and index > 0 and __nnew(v) then local groupstate_i = indexedparamvalue(args, "group%state", raw, index) if groupstate_i == "above" then local node = mw.html.create("table") :addClass("nowraplinks") :addClass("navbox-subgroup") :css("display", "table") :css("width", "100%") :cssText(__nnew(args.innerstyle)) :attr("cellspacing", 0) :attr("colspan", 2) :tag("tr"):tag("td") :addClass("navbox-group") :cssText(__nnew(args.basestyle)) :cssText(__nnew(groupstyle)) :cssText(indexedparamvalue(args, "group%state", raw, index)) :wikitext(indexedparamvalue(args, "group%", raw, index)) :done():done() :tag("tr"):tag("td") :wikitext(v) :allDone() args[k] = tostring(node) args["group"..raw] = nil args["group"..tostring(index)] = nil else local group_i = indexedparamvalue(args, "group%", raw, index) if group_i then local grouppadding_i = indexedparamvalue(args, "group%padding", raw, index) if args["group"..raw] then args["group"..raw] = tostring(mw.html.create("div") :css("padding", grouppadding_i or grouppadding or "0em 0.75em") :wikitext(args["group"..raw]) ) end if raw ~= tostring(index) and args["group"..tostring(index)] then args["group"..tostring(index)] = tostring(mw.html.create("div") :css("padding", grouppadding_i or grouppadding or "0em 0.75em") :wikitext(args["group"..tostring(index)]) ) end end end end end end return args end local function _collapsiblegroupsbox(args, frame) args[1] = args[2] args[2] = nil local selected = __nnew(args.selected) local basestyle = __nnew(args.basestyle) local groupstyle = __nnew(args.groupstyle) local secttitlestyle = __nnew(args.secttitlestyle) local liststyle = __nnew(args.liststyle) for k, v in pairs(args) do if type(k) == "string" then local raw, index = paramindexes(k, "^list%$") if index ~= nil and index > 0 and __nnew(v) then local group_i = indexedparamvalue(args, "group%", raw, index) local sect_i = indexedparamvalue(args, "sect%", raw, index) local abbr_i = indexedparamvalue(args, "abbr%", raw, index) local state_i = indexedparamvalue(args, "state%", raw, index) local groupstyle_i = indexedparamvalue(args, "group%style", raw, index) local liststyle_i = indexedparamvalue(args, "list%style", raw, index) local image_i = indexedparamvalue(args, "image%", raw, index) local imageleft_i = indexedparamvalue(args, "imageleft%", raw, index) local _args = { border = "child", state = iif(selected == abbr_i, "mw-uncollapsed", state_i or "mw-collapsed"), titlestyle = (basestyle or "")..iif(groupstyle, ";"..(groupstyle or ""), "")..iif(secttitlestyle, ";"..(secttitlestyle or ""), "")..iif(groupstyle_i, ";"..(groupstyle_i or ""), ""), liststyle = (liststyle or "")..iif(liststyle_i, ";"..(liststyle_i or ""), ""), title = group_i or sect_i, list1 = v, image = image_i, imageleft = imageleft_i } args[k] = tostring(_box(_args, frame)) args["group"..raw] = nil args["group"..tostring(index)] = nil end end end return args end local function _columnsbox(args, frame) args[1] = args[2] args[2] = nil local bodystyle = __nnew(args.bodystyle) args.style = (args.style or "")..iif(bodystyle, ";"..(bodystyle or ""), "") args.tracking = "no" local lists = {} -- 收集所有含有列的列表。 for k, v in pairs(args) do if type(k) == "string" then local lraw, craw, lindex, cindex -- list和column的raw和index。 craw, cindex = paramindexes(k, "^col%$") -- 为兼容,先检查是否存在 col+数字 格式的参数。 if cindex ~= nil then lraw, lindex = "1", 1 else -- 匹配指定列表和列的序号的参数。 lraw, craw, lindex, cindex = paramindexes(k, "^list%col%$") end if lindex ~= nil and lindex > 0 and cindex > 0 and __nnew(v) then local cols if lists[tostring(lindex)] then cols = lists[lists[tostring(lindex)]] else cols = {} table.insert(lists, cols) -- 添加新项 lists[tostring(lindex)] = #lists -- 将字符串格式的搜索键映射到对应的新项索引 lists["#"] = math.max(lists["#"] or 0, lindex) end table.insert(cols, { { lraw, craw }, { lindex, cindex }, v }) -- 添加新项 cols[tostring(cindex)] = #cols -- 将字符串格式的搜索键映射到对应的新项索引 cols["#"] = math.max(cols["#"] or 0, cindex) args[k] = nil -- 清除原有的内容以便覆写,防止影响Navbox构造逻辑。 end end end local coltablestyle = __nnew(args.coltablestyle) local fullwidth = __nnew(args.fullwidth) local colwidth = __nnew(args.colwidth) local colheaderstyle = __nnew(args.colheaderstyle) local padding = __nnew(args.padding) local colstyle = __nnew(args.colstyle) local oddcolstyle = __nnew(args.oddcolstyle) local evencolstyle = __nnew(args.evencolstyle) for lindex = 1, lists["#"] do local cols = lists[lists[tostring(lindex)]] if cols then local node = mw.html.create("table") :addClass("navbox-columns-table") :css("border-spacing", "0px") :css("text-align", "left") :cssText(coltablestyle) --if fullwidth then node = node:css("width", "100%") --else -- node = node -- :css("width", "auto") -- :css("margin-left", "auto") -- :css("margin-right", "auto") --end local header = mw.html.create("tr") -- Header row local main = mw.html.create("tr") -- Main columns local footer = mw.html.create("tr") -- Footer row local hasheader = false local hasfooter = false local visiblecol = 0 -- 计数可见的列。 for cindex = 1, cols["#"] do if cols[cols[tostring(cindex)]] then visiblecol = visiblecol + 1 -- 增加计数。 local raw, index, col_i = unpack(cols[cols[tostring(cindex)]]) local colheader_i = indexedparamvalue(args, "list%col%header", raw, index) local colfooter_i = indexedparamvalue(args, "list%col%footer", raw, index) local colstyle_i = indexedparamvalue(args, "list%col%style", raw, index) local colheadercolspan_i = indexedparamvalue(args, "list%col%headercolspan", raw, index) local colfootercolspan_i = indexedparamvalue(args, "list%col%footercolspan", raw, index) local colheaderstyle_i = indexedparamvalue(args, "list%col%headerstyle", raw, index) local colfooterstyle_i = indexedparamvalue(args, "list%col%footerstyle", raw, index) local colwidth_i = indexedparamvalue(args, "list%col%width", raw, index) if lindex == 1 then -- 如果是第一个列表,则需要考虑兼容,检查省略list1的参数名称。 colheader_i = colheader_i or indexedparamvalue(args, "col%header", raw[2], index[2]) colfooter_i = colfooter_i or indexedparamvalue(args, "col%footer", raw[2], index[2]) colstyle_i = colstyle_i or indexedparamvalue(args, "col%style", raw[2], index[2]) colheadercolspan_i = colheadercolspan_i or indexedparamvalue(args, "col%headercolspan", raw[2], index[2]) colfootercolspan_i = colfootercolspan_i or indexedparamvalue(args, "col%footercolspan", raw[2], index[2]) colheaderstyle_i = colheaderstyle_i or indexedparamvalue(args, "col%headerstyle", raw[2], index[2]) colfooterstyle_i = colfooterstyle_i or indexedparamvalue(args, "col%footerstyle", raw[2], index[2]) colwidth_i = colwidth_i or indexedparamvalue(args, "col%width", raw[2], index[2]) end --- Header row --- local hcol if colheader_i then hasheader = true hcol = header:tag("td") :addClass("navbox-abovebelow") :attr("colspan", colheadercolspan_i or 1) :css("font-weight", "bold") :cssText(colheaderstyle) :cssText(colheaderstyle_i) :wikitext(colheader_i) end --- Main columns --- main:css("vertical-align", "top") if visiblecol == 1 and not (colheader_i or colfooter_i or fullwidth) and not (padding == "off" or mw.ustring.find(padding, "^;*-?0+%a+;*$")) then main:tag("td"):css("width", padding or "5em"):wikitext(" ") end mcol = main:tag("td") :css("padding", "0px") :css("width", colwidth_i or colwidth or "10em") :cssText(colstyle) :cssText(iif(visiblecol % 2 == 1, oddcolstyle, evencolstyle)) :cssText(colstyle_i) :tag("div") :wikitext(col_i) :done() --- Footer row --- local fcol if colfooter_i then hasfooter = true fcol = footer:tag("td") :addClass("navbox-abovebelow") :att("colspan", colfootercolspan_i or 1) :css("font-weight", "bold") :cssText(colfooterstyle) :cssText(colfooterstyle_i) :wikitext(colfooter_i) end if visiblecol ~= 1 then mcol:css("border-left", "2px solid #fdfdfd") if hcol then hcol:css("border-left", "2px solid #fdfdfd") end if fcol then fcol:css("border-left", "2px solid #fdfdfd") end end end end node:node(header) -- 添加Header row。 if hasheader then node:tag("tr"):css("height", "2px"):tag("td") -- 添加header下方的分隔线。 end node:node(main) -- 添加Main columns。 if hasfooter then node:tag("tr"):css("height", "2px"):tag("td") -- 添加footer上方的分隔线。 end node:node(footer) -- 添加Footer row。 args["list"..tostring(lindex)] = tostring(node) args["list"..tostring(lindex).."style"] = "background:transparent;color:inherit;" args["list"..tostring(lindex).."padding"] = "0px" end end return args end local checkNamespaces = function(frame) if not mw.title.new(frame:getParent():getTitle()):inNamespaces( "Template" ) then return "[[Category:在非模板名字空间下的页面中调用Nav模块]]" end end local getArgs = function(frame) local _params_ = __nnew(frame.args._params_, "overwrite") if _params_ == "self" then return frame.args elseif _params_ == "overwrite" then local parent = frame:getParent() local args = {} if parent ~= nil then for k, v in pairs(parent.args) do args[k] = v end end for k, v in pairs(frame.args) do if k ~= "_params_" then args[k] = v end end return args elseif _params_ == "default" then local parent = frame:getParent() local args = {} for k, v in pairs(frame.args) do if k ~= "_params_" then args[k] = v end end if parent ~= nil then for k, v in pairs(parent.args) do args[k] = v end end return args else return nil end end function nav.box(frame) local result = checkNamespaces(frame) or "" local args = getArgs(frame) if args == nil then return require("Module:Error").error({ message = mw.ustring.format("不能识别的参数获取方式:“%s”", frame.args._params_ or "") }) end local version = __nne(args[1]) if version ~= nil then version = mw.text.trim(version) end local border = __nnew(args.border) or version if border == "subgroup" then args = _subgroupbox(args, frame) elseif version == "collapsible groups" then args = _collapsiblegroupsbox(args, frame) elseif version == "columns" then args = _columnsbox(args, frame) end return result..tostring(_box(args, frame)) end function nav.bar(frame) local result = checkNamespaces(frame) or "" local args = getArgs(frame) if args == nil then return require("Module:Error").error({ message = mw.ustring.format("不能识别的参数获取方式:“%s”", frame.args._params_ or "") }) end return result..tostring(_bar(args, frame)) end return nav