Module:Timeline
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Timeline/doc
local p = {}
function p.generateTable(frame)
-- Define the page where the events are stored
local eventsPage = mw.title.new('GlobalEvents')
-- Get the content of the events page
local eventsContent = eventsPage and eventsPage:getContent() or ''
local events = {}
local unknownEvents = {}
local sources = {}
local sourceCounter = 1
if eventsContent and eventsContent ~= '' then
-- Split the content into individual event blocks
for eventBlock in mw.text.gsplit(eventsContent, '{{EventRow', true) do
if eventBlock and eventBlock:find('|%s*date%s*=') then
local event = {}
-- Extract the date from the event block
event.date = mw.text.trim(eventBlock:match('|%s*date%s*=%s*(%d%d%d%d%-%d%d%-%d%d)') or eventBlock:match('|%s*date%s*=%s*(%d%d%d%d%-%d%d)') or eventBlock:match('|%s*date%s*=%s*(%d%d%d%d)') or eventBlock:match('|%s*date%s*=%s*(unknown)') or '')
-- Extract the title from the event block, handling newlines correctly
event.title = eventBlock:match('|%s*title%s*=%s*(.-)%s*\n') or ''
-- Extract the description from the event block, handling newlines correctly
event.description = eventBlock:match('|%s*description%s*=%s*(.-)%s*}}') or ''
-- Function to clean standalone | characters but keep them inside links
local function cleanText(text)
local cleanedText = ""
local inLink = false
for i = 1, #text do
local char = text:sub(i, i)
if char == "[" and text:sub(i, i+1) == "[[" then
inLink = true
elseif char == "]" and text:sub(i-1, i) == "]]" then
inLink = false
end
if char == "|" and not inLink then
-- skip standalone |
else
cleanedText = cleanedText .. char
end
end
return cleanedText
end
event.title = cleanText(event.title)
event.description = cleanText(event.description)
if event.date ~= '' then
if event.date == 'unknown' then
table.insert(unknownEvents, event)
else
table.insert(events, event)
end
end
end
end
-- Function to process links
local function processLinks(text)
return mw.ustring.gsub(text, "(https?://[%w%-_.~!*'();:@&=+$,/?%[%]#]+)", function(url)
local sourceTag = "[" .. sourceCounter .. "]"
table.insert(sources, "* " .. url)
sourceCounter = sourceCounter + 1
return url
end):gsub("%[(https?://[%w%-_.~!*'();:@&=+$,/?%[%]#]+)%]", function(url)
local sourceTag = "[" .. sourceCounter .. "]"
table.insert(sources, "* " .. url)
sourceCounter = sourceCounter + 1
return "[" .. url .. "] " .. sourceTag
end):gsub("%[(https?://[%w%-_.~!*'();:@&=+$,/?%[%]#]+)|([^\]]+)%]", function(url, title)
local sourceTag = "[" .. sourceCounter .. "]"
table.insert(sources, "* " .. url)
sourceCounter = sourceCounter + 1
return "[" .. url .. "|" .. title .. "] " .. sourceTag
end)
end
-- Sort the events by date in descending order, placing year-only dates before specific dates within the same year
table.sort(events, function(a, b)
local function parseDate(date)
local year, month, day = date:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
if not year then
year, month = date:match("^(%d%d%d%d)%-(%d%d)$")
day = "00"
end
if not year then
year = date:match("^(%d%d%d%d)$")
month = "00"
day = "00"
end
return year, month, day
end
local a_year, a_month, a_day = parseDate(a.date)
local b_year, b_month, b_day = parseDate(b.date)
if a_year ~= b_year then
return a_year > b_year
elseif a_month ~= b_month then
if a_month == "00" or b_month == "00" then
return a_month < b_month
else
return a_month > b_month
end
else
return a_day > b_day
end
end)
-- Function to create a table from events
local function createTable(events)
local result = '{| class="wikitable" style="width: 100%; overflow-x: auto;"\n'
result = result .. '! style="width: 120px;" | Date !! News\n'
for _, event in ipairs(events) do
local date = mw.text.nowiki(event.date or '')
local title = processLinks(frame:preprocess(event.title) or '')
local description = processLinks(frame:preprocess(event.description) or '')
-- Fix link encoding
title = title:gsub("%%7C", "|")
description = description:gsub("%%7C", "|")
result = result .. '|-\n'
result = result .. '| ' .. date .. ' || ' .. title .. '<br>' .. description .. '\n'
end
result = result .. '|}\n'
return result
end
-- Group events by year and decade
local groupedEvents = {future = {count = 0, events = {}}}
local currentYear = tonumber(os.date("%Y"))
for _, event in ipairs(events) do
local year = tonumber(event.date:sub(1, 4))
local month = tonumber(event.date:sub(6, 7))
local decade = math.floor(year / 10) * 10
if year > currentYear then
table.insert(groupedEvents.future.events, event)
groupedEvents.future.count = groupedEvents.future.count + 1
else
if not groupedEvents[decade] then
groupedEvents[decade] = {years = {}, count = 0, events = {}}
end
if not groupedEvents[decade].years[year] then
groupedEvents[decade].years[year] = {months = {}, count = 0, events = {}}
end
if not month then
month = 0 -- Assign 0 for "Exact Date Unknown"
end
if not groupedEvents[decade].years[year].months[month] then
groupedEvents[decade].years[year].months[month] = {count = 0, events = {}}
end
table.insert(groupedEvents[decade].years[year].events, event)
groupedEvents[decade].years[year].count = groupedEvents[decade].years[year].count + 1
table.insert(groupedEvents[decade].years[year].months[month].events, event)
groupedEvents[decade].years[year].months[month].count = groupedEvents[decade].years[year].months[month].count + 1
table.insert(groupedEvents[decade].events, event)
groupedEvents[decade].count = groupedEvents[decade].count + 1
end
end
-- Sort decades from newest to oldest
local sortedDecades = {}
for decade, _ in pairs(groupedEvents) do
if decade ~= "future" then
table.insert(sortedDecades, tonumber(decade))
end
end
table.sort(sortedDecades, function(a, b) return a > b end)
-- Build the result table
local result = ""
if groupedEvents.future.count > 0 then
result = result .. "\n= Future =\n"
result = result .. createTable(groupedEvents.future.events)
end
local oldestDecade = sortedDecades[#sortedDecades]
for i, decade in ipairs(sortedDecades) do
if decade ~= "future" then
local decadeData = groupedEvents[decade]
-- Sort years from newest to oldest
local sortedYears = {}
for year, _ in pairs(decadeData.years) do
table.insert(sortedYears, tonumber(year))
end
table.sort(sortedYears, function(a, b) return a > b end)
-- Adjust the title of the current decade
local endYear = (decade == math.floor(currentYear / 10) * 10) and currentYear or (decade + 9)
if decadeData.count <= 3 and decade ~= oldestDecade then
result = result .. "\n= " .. decade .. " - " .. endYear .. " =\n"
result = result .. createTable(decadeData.events)
elseif decadeData.count > 3 then
result = result .. "\n= " .. decade .. " - " .. endYear .. " =\n"
for _, year in ipairs(sortedYears) do
local yearData = decadeData.years[year]
result = result .. "\n== " .. year .. " ==\n"
if yearData.count > 3 then
-- Sort months from newest to oldest, placing "Exact Date Unknown" (month 0) after the highest month
local sortedMonths = {}
for month, _ in pairs(yearData.months) do
table.insert(sortedMonths, tonumber(month))
end
table.sort(sortedMonths, function(a, b)
if a == 0 then
return false
elseif b == 0 then
return true
else
return a > b
end
end)
for _, month in ipairs(sortedMonths) do
local monthData = yearData.months[month]
if month == 0 then
result = result .. "\n=== Exact Date Unknown (" .. year .. ") ===\n"
else
result = result .. "\n=== " .. os.date("%B %Y", os.time{year=year, month=month, day=1}) .. " ===\n"
end
result = result .. createTable(monthData.events)
end
else
result = result .. createTable(yearData.events)
end
end
else
result = result .. "\n= Before " .. (decade + 10) .. " =\n"
result = result .. createTable(decadeData.events)
end
end
end
-- Add unknown events section
if #unknownEvents > 0 then
result = result .. "\n= Date Unknown =\n"
result = result .. createTable(unknownEvents)
end
-- Add sources section
if #sources > 0 then
result = result .. "\n= Sources =\n"
for _, source in ipairs(sources) do
result = result .. source .. "\n"
end
end
return result
else
return "No events found in GlobalEvents page."
end
end
return p