Module:Timeline: Difference between revisions

From aquila
Jump to navigation Jump to search
No edit summary
mNo edit summary
Line 1: Line 1:
local p = {}
local p = {}


local dayLabels = {
-- Constant base date for Year 1, Day 1
     "Early January", "January--February", "February--March", "March--April",  
local BASE_TIMESTAMP = 1785206400 -- 2026-07-28 00:00:00 UTC
     "April--May", "May--June", "June", "June--July", "July--August",  
local SECONDS_PER_DAY = 86400
    "August--September", "September--October", "October--November",  
 
    "November--December", "Late December"
local dayNames = {
     "Early January", "January--February", "February--March", "March--April",
     "April--May", "May--June", "June", "June--July",
    "July--August", "August--September", "September--October",
    "October--November", "November--December", "Late December"
}
}
local function calculateDate(year, dayIndex)
    local daysOffset = (year - 1) * 14 + (dayIndex - 1)
    local targetTimestamp = BASE_TIMESTAMP + (daysOffset * SECONDS_PER_DAY)
    return os.date("Y-%m-%d", targetTimestamp)
end
local function formatLink(text, defaultNamespace)
    if not text or text == "" then return "" end
    text = mw.text.trim(text)
    -- If already bracketed or contains HTML/quotes, leave it
    if text:sub(1, 2) == "[[" or text:sub(1, 1) == "'" or text:sub(1, 1) == "<" then
        return text
    end
    return "[[" .."]"
end


function p.renderTable(frame)
function p.renderTable(frame)
     local year = tonumber(frame.args["Year"])
    local args = frame:getParent().args
     local category = frame.args["Category"]
     local year = tonumber(args.Year) or 1
   
     local html = ""
    local events = {}
    for i = 1, 14 do events[i] = {} end


     -- Parse parameters, but ONLY keep them if they have actual text in them
     -- We will parse 14 days. Collect events per day.
     for k, v in pairs(frame.args) do
    local schedule = {}
         local day, index, field = string.match(k, "^Day(%d+)_(%d+)_(%w+)$")
     for i = 1, 14 do
        if day and index and field then
        schedule[i] = {}
             day = tonumber(day)
         local pIdx = 1
             index = tonumber(index)
        while true do
            local post = args['Day' .. i .. '_' .. pIdx .. '_Post']
             local char = args['Day' .. i .. '_' .. pIdx .. '_Char']
             local dateOverride = args['Day' .. i .. '_' .. pIdx .. '_Date']
              
              
             if events[day][index] == nil then
             if not post or post == "" then break end
                events[day][index] = {}
            end
            events[day][index][field] = v
              
              
             -- If the Post is provided, consider this a valid event
             table.insert(schedule[i], {
            if field == "Post" and v ~= "" then
                post = post,
                events[day][index].isValid = true
                char = char or "",
             end
                date = dateOverride ~= "" and dateOverride or calculateDate(year, i)
            })
             pIdx = pIdx + 1
         end
         end
     end
     end


     -- Cleanup empty events and count valid ones
     -- Loop through days to render, handling empty range collapsing
    local validCounts = {}
    for i = 1, 14 do
        validCounts[i] = 0
        for j = 1, 20 do
            if events[i][j] and events[i][j].isValid then
                validCounts[i] = validCounts[i] + 1
            else
                events[i][j] = nil
            end
        end
    end
 
    local html = {}
    table.insert(html, '{| class="wikitable mw-collapsible" style="width: 100%; margin-top: 10px; font-size: 85%; line-height: 1.4; border-collapse: collapse;"')
    table.insert(html, '|+ Era Nova, Year ' .. year .. ' — ' .. category .. ' Timeline')
    table.insert(html, '! In-Universe Date')
    table.insert(html, '! Post')
    table.insert(html, '! Character / Nation')
    table.insert(html, '! Real-World Date')
    table.insert(html, '|-')
    table.insert(html, '! colspan="4" style="background-color: #f1f5f9; color: #0b132b; text-align: center; font-weight: bold; padding: 6px;" | ' .. string.upper(category) .. ' NEWS')
    table.insert(html, '|-')
 
    -- This loop correctly handles grouping empty dates
     local i = 1
     local i = 1
     while i <= 14 do
     while i <= 14 do
         if validCounts[i] == 0 then
         if #schedule[i] > 0 then
             -- Find how many consecutive empty days there are
             local count = #schedule[i]
             local emptySpan = 1
             local inUniverseLabel = dayNames[i] .. ", Year " .. year
             for j = i + 1, 14 do
           
                 if validCounts[j] == 0 then
             for idx, event in ipairs(schedule[i]) do
                     emptySpan = emptySpan + 1
                html = html .. "|-\n"
                 else
                 if idx == 1 then
                     break
                     html = html .. '| rowspan="' .. count .. '" | ' .. inUniverseLabel .. '\n'
                end
                html = html .. '| ' .. event.post .. '\n'
                 html = html .. '| ' .. event.char .. '\n'
                if idx == 1 then
                     html = html .. '| rowspan="' .. count .. '" | ' .. event.date .. '\n'
                 end
                 end
             end
             end
              
             i = i + 1
             local dateLabel = dayLabels[i]
        else
             if emptySpan > 1 then
            -- Scan ahead for consecutive empty days to collapse ranges
                dateLabel = dayLabels[i] .. " to<br>" .. dayLabels[i + emptySpan - 1]
             local startEmpty = i
             while i <= 14 and #schedule[i] == 0 do
                i = i + 1
             end
             end
             dateLabel = dateLabel .. ", Year " .. year
             local endEmpty = i - 1
              
              
             table.insert(html, '| ' .. dateLabel)
             local rangeLabel = ""
             table.insert(html, '| ')
            if startEmpty == endEmpty then
            table.insert(html, '| ')
                rangeLabel = dayNames[startEmpty] .. ", Year " .. year
            table.insert(html, '| ')
             else
            table.insert(html, '|-')
                rangeLabel = dayNames[startEmpty] .. " to " .. dayNames[endEmpty] .. ", Year " + year -- Note: handled cleanly below
           
                rangeLabel = dayNames[startEmpty] .. " to " .. dayNames[endEmpty] .. ", Year " .. year
            -- Skip ahead by the number of empty days we just grouped
            i = i + emptySpan
        else
            -- There are events on this day
            local rowspanAttr = ''
            if validCounts[i] > 1 then
                rowspanAttr = ' rowspan="' .. validCounts[i] .. '" '
             end
             end
              
              
             table.insert(html, '|' .. rowspanAttr .. '| ' .. dayLabels[i] .. ', Year ' .. year)
             local startDate = calculateDate(year, startEmpty)
            local endDate = calculateDate(year, endEmpty)
            local dateDisplay = (startEmpty == endEmpty) and startDate or (startDate + " to " + endDate)
            dateDisplay = (startEmpty == endEmpty) and startDate or (startDate .. " to " .. endDate)
              
              
             local rowPrinted = 0
             html = html .. "|-\n"
            for j = 1, 20 do
            html = html .. "| " .. rangeLabel .. "\n"
                local event = events[i][j]
            html = html .. "| \n"
                if event and event.isValid then
            html = html .. "| \n"
                    if rowPrinted > 0 then
            html = html .. "| " .. dateDisplay .. "\n"
                        table.insert(html, '|-')
                    end
                   
                    local postText = event.Post or ""
                    if postText ~= "" and not string.find(postText, "%[%[") then
                        postText = "[[" .. postText .. "]]"
                    end
                   
                    local charText = event.Char or ""
                    if charText ~= "" and not string.find(charText, "%[%[") then
                        charText = "[[" .. charText .. "]]"
                    end
 
                    local dateText = event.Date or ""
                    if dateText == "" then
                        local daysOffset = ((year - 1) * 14) + (i - 1)
                        local timestamp = os.time({year=2026, month=07, day=28, hour=12}) + (daysOffset * 86400)
                        dateText = os.date("%Y-%m-%d", timestamp)
                    end
 
                    table.insert(html, '| ' .. postText)
                    table.insert(html, '| ' .. charText)
                    table.insert(html, '| ' .. dateText)
                    table.insert(html, '|-')
                    rowPrinted = rowPrinted + 1
                end
            end
            i = i + 1
         end
         end
     end
     end


    table.insert(html, '|}')
     return html
     return table.concat(html, "\n")
end
end


return p
return p

Revision as of 20:33, 23 October 2026

Documentation for this module may be created at Module:Timeline/doc

local p = {}

-- Constant base date for Year 1, Day 1
local BASE_TIMESTAMP = 1785206400 -- 2026-07-28 00:00:00 UTC
local SECONDS_PER_DAY = 86400

local dayNames = {
    "Early January", "January--February", "February--March", "March--April",
    "April--May", "May--June", "June", "June--July",
    "July--August", "August--September", "September--October",
    "October--November", "November--December", "Late December"
}

local function calculateDate(year, dayIndex)
    local daysOffset = (year - 1) * 14 + (dayIndex - 1)
    local targetTimestamp = BASE_TIMESTAMP + (daysOffset * SECONDS_PER_DAY)
    return os.date("Y-%m-%d", targetTimestamp)
end

local function formatLink(text, defaultNamespace)
    if not text or text == "" then return "" end
    text = mw.text.trim(text)
    -- If already bracketed or contains HTML/quotes, leave it
    if text:sub(1, 2) == "[[" or text:sub(1, 1) == "'" or text:sub(1, 1) == "<" then
        return text
    end
    return "[[" .."]"
end

function p.renderTable(frame)
    local args = frame:getParent().args
    local year = tonumber(args.Year) or 1
    local html = ""

    -- We will parse 14 days. Collect events per day.
    local schedule = {}
    for i = 1, 14 do
        schedule[i] = {}
        local pIdx = 1
        while true do
            local post = args['Day' .. i .. '_' .. pIdx .. '_Post']
            local char = args['Day' .. i .. '_' .. pIdx .. '_Char']
            local dateOverride = args['Day' .. i .. '_' .. pIdx .. '_Date']
            
            if not post or post == "" then break end
            
            table.insert(schedule[i], {
                post = post,
                char = char or "",
                date = dateOverride ~= "" and dateOverride or calculateDate(year, i)
            })
            pIdx = pIdx + 1
        end
    end

    -- Loop through days to render, handling empty range collapsing
    local i = 1
    while i <= 14 do
        if #schedule[i] > 0 then
            local count = #schedule[i]
            local inUniverseLabel = dayNames[i] .. ", Year " .. year
            
            for idx, event in ipairs(schedule[i]) do
                html = html .. "|-\n"
                if idx == 1 then
                    html = html .. '| rowspan="' .. count .. '" | ' .. inUniverseLabel .. '\n'
                end
                html = html .. '| ' .. event.post .. '\n'
                html = html .. '| ' .. event.char .. '\n'
                if idx == 1 then
                    html = html .. '| rowspan="' .. count .. '" | ' .. event.date .. '\n'
                end
            end
            i = i + 1
        else
            -- Scan ahead for consecutive empty days to collapse ranges
            local startEmpty = i
            while i <= 14 and #schedule[i] == 0 do
                i = i + 1
            end
            local endEmpty = i - 1
            
            local rangeLabel = ""
            if startEmpty == endEmpty then
                rangeLabel = dayNames[startEmpty] .. ", Year " .. year
            else
                rangeLabel = dayNames[startEmpty] .. " to " .. dayNames[endEmpty] .. ", Year " + year -- Note: handled cleanly below
                rangeLabel = dayNames[startEmpty] .. " to " .. dayNames[endEmpty] .. ", Year " .. year
            end
            
            local startDate = calculateDate(year, startEmpty)
            local endDate = calculateDate(year, endEmpty)
            local dateDisplay = (startEmpty == endEmpty) and startDate or (startDate + " to " + endDate)
            dateDisplay = (startEmpty == endEmpty) and startDate or (startDate .. " to " .. endDate)
            
            html = html .. "|-\n"
            html = html .. "| " .. rangeLabel .. "\n"
            html = html .. "| \n"
            html = html .. "| \n"
            html = html .. "| " .. dateDisplay .. "\n"
        end
    end

    return html
end

return p