2023年政策修订增补工作正在进行中,欢迎参与!
Module:VersionHistory
跳转到导航
跳转到搜索
local module = {}
local getArgs = require('Module:Arguments').getArgs
function module.funcSelector(frame)
local args = getArgs(frame)
local funcName = args["_funcName"]
if funcName == "main" then
return module.main(args)
elseif funcName == "entry" then
return module.entry(args)
end
end
function module.main(args)
local doc = {}
if args["docname"] == nil then
for i, line in ipairs(args) do
for _i, entry in ipairs(module.parseEntries(line)) do
table.insert(doc, entry)
end
end
else
local docname = args["docname"]
local v1, v2 = mw.ustring.find(docname, ":")
local title = mw.title.makeTitle(mw.ustring.sub(docname, 1, v1 - 1), mw.ustring.sub(docname, v2 + 1, mw.ustring.len(docname)))
local doccontent = title:getContent() --读取JSON格式的版本历史元数据页的所有内容。
doc = mw.text.jsonDecode(doccontent)
end
for i, entry in ipairs(doc) do module.normalizeEntry(entry) end --标准化版本历史项。
return module.output(doc, args)
end
function module.entry(args)
local entry = {}
if args["version"] ~= nil then entry.version = args["version"] end
if args["time"] ~= nil then entry.time = args["time"] end
if args["summary"] ~= nil then
entry.summary = mw.ustring.gsub(args["summary"], ";", "//;//")
if args["details"] ~= nil then
entry.details = mw.ustring.gsub(args["details"], ";", "//;//")
end
end
module.normalizeEntry(entry)
local output = args["output"]
if output == "json" then
return mw.text.jsonEncode(entry)
else
return mw.ustring.format("version:%s;time:%s;summary:%s;details:%s", entry.version, entry.time, entry.summary, entry.details)
end
end
function module.output(doc, args)
table.sort(doc,
function(e1, e2)
if e1.version ~= nil and e2.version ~= nil then return e1.version < e2.version
elseif e1.time ~= nil and e2.time ~= nil then return e1.time < e2.time
else return true
end
end
)
local output = args["output"]
if output == "json" then
return mw.text.jsonEncode(doc)
else
local rLines = {}
for i, entry in ipairs(doc) do
local frame = mw.getCurrentFrame()
local iif = function(value, valueWhenNil)
if value == nil then return valueWhenNil
else return value
end
end
local savefunc = function(condition, func)
if condition == nil then return nil
else return func(condition)
end
end
local fullurl = savefunc(entry.version, function()
return frame:callParserFunction("fullurl", { args["pagename"], "oldid="..entry.version })
end)
local timeStr = iif(savefunc(entry.time, function()
return frame:callParserFunction("#time", { "Y年m月d日 (D) H:i", entry.time })
end), "<时间数据丢失>")
local linkStr
if fullurl == nil then
linkStr = timeStr
else
linkStr = mw.ustring.format("[%s %s]", fullurl, timeStr)
end
local descriptionStr
if entry.summary == nil then
descriptionStr = ""
else
local span_summary = mw.html.create("span")
span_summary:wikitext(frame:preprocess(entry.summary))
if entry.details == nil then
descriptionStr = tostring(span_summary)
else
span_summary:attr("class", toggleid)
:attr("style", "cursor:pointer")
:attr("title", args["pagename"])
local div_details = mw.html.create("div")
div_details:attr("class", "mw-collapsible mw-collapsed")
:attr("id", toggleid)
:wikitext(frame:preprocess(entry.details))
local widgetInvoke = frame:callParserFunction("#Widget", { "Toggle" })
descriptionStr = mw.ustring.format("%s%s%s", tostring(span_summary), tostring(div_details), widgetInvoke)
end
end
table.insert(rLines, mw.ustring.format("*%s %s", linkStr, descriptionStr))
end
return table.concat(rLines, "\r\n")
end
end
function module.parseEntries(str)
str = mw.text.unstripNoWiki(str)
str = mw.text.decode(str)
local entryStrs = module.splitWithEscape(str, "///;\\\\\\", "//////;\\\\\\\\\\\\")
local entries = {}
for i, entryStr in ipairs(entryStrs) do
if mw.text.trim(entryStr) ~= "" then
local version, time, summary, details
local splitResult = module.splitWithEscape(entryStr, ";", "//;//")
for _i, v in ipairs(splitResult) do
local v1, v2 = mw.ustring.find(v, ":", nil, true)
if v1 ~= nil then
local key = mw.ustring.sub(v, 1, v1 - 1)
local value = mw.ustring.sub(v, v2 + 1, mw.ustring.len(v))
if key == "version" then
version = value
elseif key == "time" then
time = value
elseif key == "summary" then
summary = value
elseif key == "details" then
details = value
end
end
end
if version ~= nil or time ~= nil or summary ~= nil or details ~= nil then
table.insert(entries, { version = version, time = time, summary = summary, details = details })
end
end
end
return entries
end
function module.splitWithEscape(str, separator, escape)
if str == nil then error("str的值为nil。") end
if separator == nil then error("separator的值为nil。") end
if escape == nil then error("escape的值为nil。") end
local v1, v2 = mw.ustring.find(escape, separator, 1, true)
if v1 == nil then error("separator应为escape的一部分") end
local preLen = v1 - 1
local sufLen = mw.ustring.len(escape) - v2
local result = {}
local p_start = 1
local p_buffer = p_start
local length = mw.ustring.len(str)
while p_start < length do
v1, v2 = mw.ustring.find(str, separator, p_buffer, true)
if v1 == nil then break --不再有分隔符
elseif (v1 < p_buffer + preLen or v2 > length - sufLen) or mw.ustring.sub(str, v1 - preLen, v2 + sufLen) ~= escape then --不是转义序列
--分割字符串
temp_escapedStr = mw.ustring.gsub(mw.ustring.sub(str, p_start, v1 - 1), escape, separator)
table.insert(result, temp_escapedStr)
--更新起始指针和缓存指针
p_start = v2 + 1
p_buffer = p_start
else --是转义序列
--更新缓存指针
p_buffer = v2 + sufLen + 1
end
end
temp_escapedStr = mw.ustring.gsub(mw.ustring.sub(str, p_start, length), escape, separator)
table.insert(result, temp_escapedStr)
return result
end
function module.normalizeEntry(entry)
if entry == nil then error("entry的值为nil。") end
if entry.version ~= nil then
entry.version = mw.ustring.match(tostring(entry.version), "%d+")
end
if entry.time ~= nil then
entry.time = module.time2timeStr(module.timeStr2time(entry.time))
end
if entry.summary == nil and entry.details ~= nil then
entry.details = nil
end
end
function module.timeStr2time(timeStr)
if timeStr == nil then error("timeStr为空") end
if type(timeStr) ~= "string" then error("timeStr的类型不是函数接受的参数类型") end
local year, month, day, hour, min
if year == nil then year, month, day, hour, min = mw.ustring.match(timeStr, "(%d+)年(%d+)月(%d+)日 %([日一二三四五六]%) (%d+):(%d+)") end
if year == nil then year, month, day, hour, min = mw.ustring.match(timeStr, "(%d+)-(%d+)-(%d+)T(%d+):(%d+):%d+Z") end
if year == nil then year, month, day, hour, min = mw.ustring.match(timeStr, "(%d+)-(%d+)-(%d+) (%d+):(%d+)") end
if year == nil then error("time格式不正确。") end
if year == nil then return nil
else return { year = tonumber(year), month = tonumber(month), day = tonumber(day), hour = tonumber(hour), min = tonumber(min) }
end
end
function module.time2timeStr(time)
if time == nil then error("time为空") end
if type(time) ~= "table" then error("time的类型不是函数接受的参数类型") end
return os.date("%Y-%m-%d %H:%M", os.time(time))
end
return module