Module:Infobox/new
来自Vocawiki
更多操作
模块文档
用于{{Infobox/new}}
local p = {}
-- 参数别名
local ALIASES = {
title = { "标题", "標題" },
image = { "图片", "圖片" },
size = { "图片大小", "圖片大小" },
caption = { "图片说明", "圖片說明", "图片信息", "圖片信息" },
tabs = {},
float = {},
class = {},
order = {},
["title-bg"] = { "标题背景色", "標題背景色" },
["title-color"] = { "标题文字色", "標題文字色" },
["header-bg"] = { "横栏背景色", "橫欄背景色" },
["header-color"] = { "横栏文字色", "橫欄文字色" },
["label-bg"] = { "标签背景色", "標籤背景色" },
["label-color"] = { "标签文字色", "標籤文字色" },
collapsible = {},
collapsed = {},
["data-align"] = { "数据对齐", "資料對齊" },
}
local CANON = {}
for std, aliases in pairs(ALIASES) do
CANON[std] = std
for _, a in ipairs(aliases) do CANON[a] = std end
end
local DEFAULTS = { size = "300px", float = "right" }
-- trim,空串返回nil
local function trim(s)
if type(s) ~= "string" then return nil end
s = mw.text.trim(s)
return s ~= "" and s or nil
end
local function is_present(s)
return type(s) == "string" and mw.text.trim(s) ~= ""
end
-- 准备文本
local function prep_wikitext(text)
if not text or text == "" then return text end
if text:match("^[*#;:%{|!]") then text = "\n" .. text end
text = text:gsub("\n([^*#;:%{|!])", " %1")
return text
end
-- 解析order
local function parse_order(s)
local list = {}
if not s then return list end
for item in mw.text.gsplit(s, "%s*,%s*") do
item = mw.text.trim(item)
if item ~= "" then
local c = mw.ustring.sub(item, 1, 1)
if c == "-" then
list[#list + 1] = { kind = "header", key = mw.ustring.sub(item, 2) }
elseif c == "_" then
list[#list + 1] = { kind = "free", key = mw.ustring.sub(item, 2) }
else
list[#list + 1] = { kind = "data", key = item }
end
end
end
return list
end
-- header后是否还有可见内容
local function has_content_after(fields, start_idx, args)
for i = start_idx + 1, #fields do
local f = fields[i]
if f.kind == "data" then
if is_present(args[f.key]) then return true end
elseif f.kind == "free" then
return true
end
end
return false
end
local function header_text(f, args)
return trim(args["-" .. f.key]) or f.key
end
local function free_text(f, args)
return trim(args["_" .. f.key]) or f.key
end
-- 构建内联CSS
local function css(map)
local parts = {}
for k, v in pairs(map) do
if v then parts[#parts + 1] = k .. ":" .. v end
end
return next(parts) and table.concat(parts, ";") or nil
end
-- 解析折叠节号
local function parse_collapsed(raw)
local set = {}
if raw then
for n in mw.text.gsplit(raw, "%s*,%s*") do
n = tonumber(mw.text.trim(n))
if n then set[n] = true end
end
end
return set
end
-- 构建信息栏
local function build(args)
local float = trim(args["float"]) or DEFAULTS.float
local extra = trim(args["class"])
local root = mw.html.create("div")
:addClass("infobox")
:addClass("infobox-float-" .. float)
if extra then root:addClass(extra) end
local data_align = trim(args["data-align"])
if data_align then root:addClass("infobox-data-" .. data_align) end
-- 主表格
local main = root:tag("table"):addClass("infobox-main")
local title = trim(args["title"])
if title then
local s = css { background = trim(args["title-bg"]), color = trim(args["title-color"]) }
main:tag("tr"):addClass("infobox-title")
:tag("th"):attr("colspan", "2")
:cssText(s)
:wikitext(title)
end
local tabs_val = trim(args["tabs"])
local img_val = trim(args["image"])
if tabs_val or img_val then
local td = main:tag("tr"):addClass("infobox-image")
:tag("td"):attr("colspan", "2")
if tabs_val then
td:wikitext(tabs_val)
else
td:wikitext(string.format("[[File:%s|%s|class=infobox-img]]",
img_val, trim(args["size"]) or DEFAULTS.size))
end
end
local cap = trim(args["caption"])
if cap then
main:tag("tr"):addClass("infobox-caption")
:tag("td"):attr("colspan", "2")
:wikitext(cap)
end
-- 数据区域
local fields = parse_order(trim(args["order"]))
if #fields == 0 then return tostring(root) end
local collapsible = trim(args["collapsible"]) ~= "0" and trim(args["collapsible"]) ~= "no"
local collapsed_set = parse_collapsed(trim(args["collapsed"]))
local header_css = css { background = trim(args["header-bg"]), color = trim(args["header-color"]) }
local label_css = css { background = trim(args["label-bg"]), color = trim(args["label-color"]) }
local section_id = 0
local cur_tbl = nil
local function flush()
if cur_tbl then root:node(cur_tbl); cur_tbl = nil end
end
local function new_data_table(can_collapse)
local tbl = mw.html.create("table"):addClass("infobox-section")
if can_collapse then
tbl:addClass("mw-collapsible")
if collapsed_set[section_id] then tbl:addClass("mw-collapsed") end
tbl:attr("id", "mw-customcollapsible-" .. section_id)
end
return tbl
end
for i, f in ipairs(fields) do
if f.kind == "header" then
if has_content_after(fields, i, args) then
flush()
section_id = section_id + 1
local hdr_tbl = mw.html.create("table"):addClass("infobox-section")
local hdr_tr = hdr_tbl:tag("tr"):addClass("infobox-header")
if collapsible then hdr_tr:addClass("mw-customtoggle-" .. section_id) end
hdr_tr:tag("th"):attr("colspan", "2")
:cssText(header_css)
:wikitext(prep_wikitext(header_text(f, args)))
:tag("span"):addClass("infobox-collapse-icon")
root:node(hdr_tbl)
cur_tbl = new_data_table(collapsible)
end
elseif f.kind == "free" then
if not cur_tbl then cur_tbl = new_data_table(false) end
cur_tbl:tag("tr"):addClass("infobox-full")
:tag("td"):attr("colspan", "2")
:wikitext(prep_wikitext(free_text(f, args)))
else -- data
local val = trim(args[f.key])
if val then
if not cur_tbl then cur_tbl = new_data_table(false) end
local row = cur_tbl:tag("tr"):addClass("infobox-row")
row:tag("td"):addClass("infobox-label")
:cssText(label_css)
:wikitext(f.key)
row:tag("td"):addClass("infobox-data")
:wikitext(prep_wikitext(val))
end
end
end
flush()
return tostring(root)
end
-- 合并参数并解析别名
local function merge_args(frame)
local args = {}
local parent = frame:getParent()
if parent then
for k, v in pairs(parent.args) do
local val, raw = trim(v), trim(tostring(k))
if val and raw then
local m = CANON[mw.ustring.lower(raw)]
args[m or raw] = val
end
end
end
for k, v in pairs(frame.args) do
local val, raw = trim(v), trim(tostring(k))
if val and raw then
local m = CANON[mw.ustring.lower(raw)]
args[m or raw] = val
end
end
return args
end
-- 入口:显式order
function p.render(frame)
return build(merge_args(frame))
end
-- 入口:自动模式
function p.main(frame)
local args = merge_args(frame)
if not trim(args["order"]) then
local allkeys = trim(frame.args["__allkeys"])
if allkeys then
local order = {}
for key in mw.text.gsplit(allkeys, "%s*,%s*") do
local k = trim(key)
if k and not CANON[mw.ustring.lower(k)] then
order[#order + 1] = k
end
end
args["order"] = table.concat(order, ", ")
end
end
return build(args)
end
-- 返回所有控制参数名
function p.controlParams(frame)
local list = {}
for std, aliases in pairs(ALIASES) do
list[#list + 1] = std
for _, a in ipairs(aliases) do list[#list + 1] = a end
end
return table.concat(list, "|")
end
return p