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