此模块的文档可以在Module:时间线/doc创建

-- Module:Timeline
-- Made with ♥ by User:Leranjun
-- Modified with ♥ by User:Liliaceae

-- This module implements {{tl|Timeline}}.
-- Please refrain from invoking this module directly.

local p = {}

local getArgs = require("Module:Arguments").getArgs
local splitString = require('Module:Split2')

local function notempty(s)
    return (s and s ~= "")
end

local function procKeys(inputArgs)
    local newArgs = {}
    local numberKeys = {}
    
    for key, _ in pairs(inputArgs) do
        if type(key) == "number" then
            table.insert(numberKeys, key)
        end
    end
    table.sort(numberKeys)
    
    for newIndex, oldKey in ipairs(numberKeys) do
        newArgs[newIndex] = inputArgs[oldKey]
    end
    
    for key, val in pairs(inputArgs) do
        if type(key) ~= "number" then
            newArgs[key] = val
        end
    end
    
    return newArgs
end

local function hasInPrefix(t)
    for k, _ in pairs(t) do
        if type(k) == "string" and k:sub(1, 2) == "in" then
            return true
        end
    end
    return false
end

function p.main(frame)
	local args = getArgs(frame, {
		parentFirst = true,
	})
    return p._main(args)
end

function p._main(args)
    local anchor = (mw.ustring.lower((args.anchor or "yes")) ~= "no")

    local r = mw.html.create("table"):addClass("timeline"):addClass(args.class):cssText(args.style)

    local data = p.parse(p.preparse(args))

    for _, period in ipairs(data[1]) do
        local timelist = data[period]
        if (notempty(period)) then
            local row = mw.html.create("tr")
            local header =
                mw.html.create("th"):attr("colspan", 3):cssText(args.periodstyle):cssText(args[period .. "style"])
            if (anchor) then
                local heading =
                    mw.html.create("h5"):cssText("display:inline;font-weight:inherit;color:inherit"):wikitext(period)
                header:node(tostring(heading))
            else
                header:wikitext(period)
            end
            row:node(tostring(header))
            r:node(tostring(row))
        end

        for _, time in ipairs(timelist[1]) do
            local events = timelist[time]
            local long = events.l
            local cnt = #events
            local full = period .. time
            for cur, event in ipairs(events) do
                local row = mw.html.create("tr")
                local cell = mw.html.create("td"):cssText(args.textstyle):cssText(args[full .. "textstyle"])
                if (not long) then
                    cell:attr("colspan", 2)
                end
                -- Add line breaks to fix compatibility issues with unordered lists
                cell:wikitext(event .. "\n")

                if (cur == 1) then
                    local header =
                        mw.html.create("th"):css("font-weight", args.timeweight):cssText(args.timestyle):cssText(
                        args[full .. "style"]
                    )

                    if (long) then
                        header:attr("colspan", 2)
                    end

                    if (cnt > 1) then
                        header:attr("rowspan", cnt)
                    end

                    if (args.period == "on") then
                        header:wikitext(period)
                    end
                    header:wikitext(time)
                    header:wikitext(args.sepr or "")

                    row:node(tostring(header))
                end
                row:node(tostring(cell))
                r:node(tostring(row))
            end
        end
    end

    return r
end

function p.preparse(args)
	local arg = procKeys(args)
	local code = ''
	local counter = 0
	local pat = ""
	local argVal = {}
	if hasInPrefix(arg) == true then
		mw.addWarning("可能缺少参数或数据格式不正确!请查阅模板文档。")
	end
	for index, val in ipairs(arg) do
		local result = mw.ustring.find(val, "in", 1)
		if(result == 1) then 
			if(counter == 0) then
				code = code .. ":"
			end
			local moe1 = splitString.split(val, '::', 0)
			if moe1 ~= nil and moe1.count == 2 then
				result, _ = mw.ustring.gsub(moe1.parts[1], "in", "", 1)
				result, _ = mw.ustring.gsub(result, pat, "", 1)
				code = code .. result .. ","
				argVal["in" .. pat .. result] = moe1.parts[2]
			else
				mw.addWarning("缺少参数或数据格式不正确!")
			end
		else
			if(counter ~= 0) then
				code = code .. ";"
			end
			code = code .. val .. ":"
			pat = val
		end
		counter = counter + 1
	end
	return {code .. ";", argVal}
end

function p.parse(args)
    local raw = args[1]
    local args2 = args[2]
    local data = {[1] = {}} -- index

    for v in mw.text.gsplit(raw, ";") do
        if (not notempty(v)) then
            break
        end

        local timelist = mw.text.split(v, ":")
        local period = timelist[1]
        timelist = timelist[2]

        data[period] = {[1] = {}}
        table.insert(data[1], period)

        for time in mw.text.gsplit(timelist, ",") do
            if (not notempty(time)) then
                break
            end

            local value = args2["in" .. period .. time]
            time = mw.text.split(time, "#")
            local needSort = false
            if (#time == 1) then
                needSort = true
            end
            time = time[1]

            time = mw.text.split(time, "in")
            if (#time > 1) then
                time = time[2]
                data[period][time] = data[period][time] or {l = true}
            else
                time = time[1]
                data[period][time] = data[period][time] or {}
            end

            if (needSort) then
                table.insert(data[period][1], time)
            end

            table.insert(data[period][time], value)
        end
    end

    return data
end

return p