Module:Timeline: Difference between revisions
Jump to navigation
Jump to search
mNo edit summary |
mNo edit summary Tag: Reverted |
||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local | local dayLabels = { | ||
"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" | |||
} | } | ||
function p.render(frame) | |||
local year = tonumber(frame.args["Year"]) | |||
local category = frame.args["Category"] | |||
local categoryUpper = string.upper(category) | |||
-- Fetch data from Cargo | |||
local cargoQuery = frame:callParserFunction('#cargo_query', { | |||
tables = 'NewsPosts', | |||
fields = 'Page_Name,Title,Type,RealDate,Author,Publisher,DayNum', | |||
where = 'YearNum=' .. tostring(year) .. ' AND Type="' .. categoryUpper .. ' News"', | |||
order_by = 'DayNum ASC, RealDate ASC' | |||
}) | |||
-- Parse Cargo results | |||
local | |||
local | |||
local | |||
local | |||
local events = {} | local events = {} | ||
for i = 1, 14 do events[i] = {} end | |||
local | |||
-- Simple parser for Cargo's template output | |||
local rows = {} | |||
local | for row in string.gmatch(cargoQuery, "<tr>(.-)</tr>") do | ||
if | local title, page, author, publisher, day = string.match(row, "<td>(.-)</td><td>(.-)</td><td>(.-)</td><td>(.-)</td><td>(.-)</td>") | ||
if day then | |||
local d = tonumber(day) | |||
if d and d >= 1 and d <= 14 then | |||
table.insert(events[d], { | |||
Post = title, | |||
Page = page, | |||
Char = author ~= "" and author or publisher, | |||
Date = "Auto" -- Handled by Cargo real date if needed | |||
}) | |||
end | |||
end | end | ||
end | end | ||
for | -- Add manual events from Day1...Day14 parameters | ||
local | for i = 1, 14 do | ||
local manualData = frame.args["Day" .. i] | |||
if manualData and manualData ~= "" then | |||
for line in string.gmatch(manualData, "[^\r\n]+") do | |||
local post, char = string.match(line, "^%s*(.-)%s*;%s*(.-)%s*$") | |||
if post and post ~= "" then | |||
table.insert(events[i], { Post = post, Char = char or "" }) | |||
elseif post == nil and line ~= "" then | |||
table.insert(events[i], { Post = line, Char = "" }) | |||
end | |||
end | |||
end | end | ||
end | end | ||
-- Build the HTML table | |||
local html = {} | |||
-- Determine accent color based on category | |||
local | local headerBg = "#3a506b" -- Default slate | ||
if categoryUpper == "CHARACTER" then headerBg = "#6e473b" end | |||
table.insert(html, '<div class="aquila-timeline-custom" style="border: 1px solid #d1d5db; border-radius: 12px; overflow: hidden; margin-bottom: 2em; box-shadow: 0 4px 12px rgba(0,0,0,0.05);">') | |||
-- Table Header | |||
table.insert(html, '<table style="width: 100%; border-collapse: collapse; background: #ffffff; margin: 0;">') | |||
table.insert(html, '<tr>') | |||
table.insert(html, '<th colspan="4" style="background: ' .. headerBg .. '; color: #ffffff; font-family: \'Georgia\', serif; font-size: 1.1em; letter-spacing: 0.1em; text-align: center; padding: 12px; border-bottom: 3px solid #e0a96d;">' .. categoryUpper .. ' NEWS</th>') | |||
table.insert(html, '</tr>') | |||
-- Column Headers | |||
table.insert(html, '<tr>') | |||
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 20%;">In-universe date</th>') | |||
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 35%;">Post</th>') | |||
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 25%;">Character / nation</th>') | |||
for | table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 20%;">Real-world date</th>') | ||
table.insert(html, '</tr>') | |||
-- Loop through days | |||
local skipRows = 0 | |||
for i = 1, 14 do | |||
if skipRows > 0 then | |||
skipRows = skipRows - 1 | |||
else | |||
local eventCount = #events[i] | |||
if eventCount == 0 then | |||
-- Empty Day Logic | |||
local emptySpan = 1 | |||
for j = i + 1, 14 do | |||
if #events[j] == 0 then | |||
emptySpan = emptySpan + 1 | |||
else | |||
break | |||
end | |||
end | |||
local dateLabel = dayLabels[i] | |||
if emptySpan > 1 then | |||
dateLabel = dayLabels[i] .. " to " .. dayLabels[i + emptySpan - 1] | |||
end | |||
dateLabel = dateLabel .. ", Year " .. year | |||
table.insert(html, '<tr style="background: #fcfcfd;">') | |||
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; color: #64748b; font-style: italic; font-size: 0.9em;">' .. dateLabel .. '</td>') | |||
table.insert(html, '<td colspan="3" style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; color: #94a3b8; font-style: italic;">No news</td>') | |||
table.insert(html, '</tr>') | |||
skipRows = emptySpan - 1 | |||
else | else | ||
-- Event Logic | |||
local rowspanAttr = '' | |||
if eventCount > 1 then | |||
rowspanAttr = ' rowspan="' .. eventCount .. '" ' | |||
end | end | ||
for idx, event in ipairs(events[i]) do | |||
table.insert(html, '<tr style="background: #ffffff; transition: background 0.2s;">') | |||
-- Date Column (Only on first row of the day) | |||
if idx == 1 then | |||
) | table.insert(html, '<td' .. rowspanAttr .. 'style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; border-right: 1px solid #e2e8f0; font-weight: bold; color: #1e293b; vertical-align: top;">' .. dayLabels[i] .. ', Year ' .. year .. '</td>') | ||
end | |||
-- Post Column | |||
local postText = event.Post | |||
if event.Page and event.Page ~= "" then | |||
postText = '[[' .. event.Page .. '|' .. event.Post .. ']]' | |||
elseif not string.find(postText, "%[%[") and not string.find(postText, "<span>") then | |||
postText = '[[' .. postText .. ']]' | |||
end | |||
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; border-right: 1px solid #e2e8f0; vertical-align: top;">' .. postText .. '</td>') | |||
-- Character Column | |||
local charText = event.Char or "" | |||
if charText ~= "" and not string.find(charText, "%[%[") and not string.find(charText, "<span>") then | |||
charText = '[[' .. charText .. ']]' | |||
end | |||
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; border-right: 1px solid #e2e8f0; vertical-align: top;">' .. charText .. '</td>') | |||
-- Date Column | |||
local realDate = event.Date or "" | |||
if realDate == "Auto" then | |||
local daysOffset = ((year - 1) * 14) + (i - 1) | |||
local timestamp = os.time({year=2026, month=07, day=28, hour=12}) + (daysOffset * 86400) | |||
realDate = os.date("%Y-%m-%d", timestamp) | |||
end | |||
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; vertical-align: top; color: #64748b; font-size: 0.9em; white-space: nowrap;">' .. realDate .. '</td>') | |||
table.insert(html, '</tr>') | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
return html | |||
table.insert(html, '</table>') | |||
table.insert(html, '</div>') | |||
return table.concat(html, "\n") | |||
end | end | ||
return p | return p | ||
Revision as of 10:40, 24 October 2026
Documentation for this module may be created at Module:Timeline/doc
local p = {}
local dayLabels = {
"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"
}
function p.render(frame)
local year = tonumber(frame.args["Year"])
local category = frame.args["Category"]
local categoryUpper = string.upper(category)
-- Fetch data from Cargo
local cargoQuery = frame:callParserFunction('#cargo_query', {
tables = 'NewsPosts',
fields = 'Page_Name,Title,Type,RealDate,Author,Publisher,DayNum',
where = 'YearNum=' .. tostring(year) .. ' AND Type="' .. categoryUpper .. ' News"',
order_by = 'DayNum ASC, RealDate ASC'
})
-- Parse Cargo results
local events = {}
for i = 1, 14 do events[i] = {} end
-- Simple parser for Cargo's template output
local rows = {}
for row in string.gmatch(cargoQuery, "<tr>(.-)</tr>") do
local title, page, author, publisher, day = string.match(row, "<td>(.-)</td><td>(.-)</td><td>(.-)</td><td>(.-)</td><td>(.-)</td>")
if day then
local d = tonumber(day)
if d and d >= 1 and d <= 14 then
table.insert(events[d], {
Post = title,
Page = page,
Char = author ~= "" and author or publisher,
Date = "Auto" -- Handled by Cargo real date if needed
})
end
end
end
-- Add manual events from Day1...Day14 parameters
for i = 1, 14 do
local manualData = frame.args["Day" .. i]
if manualData and manualData ~= "" then
for line in string.gmatch(manualData, "[^\r\n]+") do
local post, char = string.match(line, "^%s*(.-)%s*;%s*(.-)%s*$")
if post and post ~= "" then
table.insert(events[i], { Post = post, Char = char or "" })
elseif post == nil and line ~= "" then
table.insert(events[i], { Post = line, Char = "" })
end
end
end
end
-- Build the HTML table
local html = {}
-- Determine accent color based on category
local headerBg = "#3a506b" -- Default slate
if categoryUpper == "CHARACTER" then headerBg = "#6e473b" end
table.insert(html, '<div class="aquila-timeline-custom" style="border: 1px solid #d1d5db; border-radius: 12px; overflow: hidden; margin-bottom: 2em; box-shadow: 0 4px 12px rgba(0,0,0,0.05);">')
-- Table Header
table.insert(html, '<table style="width: 100%; border-collapse: collapse; background: #ffffff; margin: 0;">')
table.insert(html, '<tr>')
table.insert(html, '<th colspan="4" style="background: ' .. headerBg .. '; color: #ffffff; font-family: \'Georgia\', serif; font-size: 1.1em; letter-spacing: 0.1em; text-align: center; padding: 12px; border-bottom: 3px solid #e0a96d;">' .. categoryUpper .. ' NEWS</th>')
table.insert(html, '</tr>')
-- Column Headers
table.insert(html, '<tr>')
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 20%;">In-universe date</th>')
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 35%;">Post</th>')
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 25%;">Character / nation</th>')
table.insert(html, '<th style="background: #f8fafc; color: #1e293b; font-family: \'Georgia\', serif; padding: 10px; text-align: left; border-bottom: 2px solid #e2e8f0; width: 20%;">Real-world date</th>')
table.insert(html, '</tr>')
-- Loop through days
local skipRows = 0
for i = 1, 14 do
if skipRows > 0 then
skipRows = skipRows - 1
else
local eventCount = #events[i]
if eventCount == 0 then
-- Empty Day Logic
local emptySpan = 1
for j = i + 1, 14 do
if #events[j] == 0 then
emptySpan = emptySpan + 1
else
break
end
end
local dateLabel = dayLabels[i]
if emptySpan > 1 then
dateLabel = dayLabels[i] .. " to " .. dayLabels[i + emptySpan - 1]
end
dateLabel = dateLabel .. ", Year " .. year
table.insert(html, '<tr style="background: #fcfcfd;">')
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; color: #64748b; font-style: italic; font-size: 0.9em;">' .. dateLabel .. '</td>')
table.insert(html, '<td colspan="3" style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; color: #94a3b8; font-style: italic;">No news</td>')
table.insert(html, '</tr>')
skipRows = emptySpan - 1
else
-- Event Logic
local rowspanAttr = ''
if eventCount > 1 then
rowspanAttr = ' rowspan="' .. eventCount .. '" '
end
for idx, event in ipairs(events[i]) do
table.insert(html, '<tr style="background: #ffffff; transition: background 0.2s;">')
-- Date Column (Only on first row of the day)
if idx == 1 then
table.insert(html, '<td' .. rowspanAttr .. 'style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; border-right: 1px solid #e2e8f0; font-weight: bold; color: #1e293b; vertical-align: top;">' .. dayLabels[i] .. ', Year ' .. year .. '</td>')
end
-- Post Column
local postText = event.Post
if event.Page and event.Page ~= "" then
postText = '[[' .. event.Page .. '|' .. event.Post .. ']]'
elseif not string.find(postText, "%[%[") and not string.find(postText, "<span>") then
postText = '[[' .. postText .. ']]'
end
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; border-right: 1px solid #e2e8f0; vertical-align: top;">' .. postText .. '</td>')
-- Character Column
local charText = event.Char or ""
if charText ~= "" and not string.find(charText, "%[%[") and not string.find(charText, "<span>") then
charText = '[[' .. charText .. ']]'
end
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; border-right: 1px solid #e2e8f0; vertical-align: top;">' .. charText .. '</td>')
-- Date Column
local realDate = event.Date or ""
if realDate == "Auto" then
local daysOffset = ((year - 1) * 14) + (i - 1)
local timestamp = os.time({year=2026, month=07, day=28, hour=12}) + (daysOffset * 86400)
realDate = os.date("%Y-%m-%d", timestamp)
end
table.insert(html, '<td style="padding: 12px 10px; border-bottom: 1px solid #e2e8f0; vertical-align: top; color: #64748b; font-size: 0.9em; white-space: nowrap;">' .. realDate .. '</td>')
table.insert(html, '</tr>')
end
end
end
end
table.insert(html, '</table>')
table.insert(html, '</div>')
return table.concat(html, "\n")
end
return p