Module:Events: Difference between revisions
From Deepspace Lore
More actions
Created page with "local p = {} -- Store event data into Bucket, called via Template:EventStore function p.store(frame) local args = frame.args -- Split characters string on ; into a table local characters = {} if args.characters and args.characters ~= "" then for c in args.characters:gmatch("[^;]+") do table.insert(characters, c:match("^%s*(.-)%s*$")) -- trim whitespace end end bucket("events").put({ name = args.name..." |
No edit summary |
||
| (One intermediate revision by the same user not shown) | |||
| Line 1: | Line 1: | ||
local p = {} | local p = {} | ||
local getArgs = require('Module:Arguments').getArgs | |||
-- | -- ============================================================================ | ||
function p. | -- CONFIGURATION | ||
local | -- ============================================================================ | ||
local ALL_CHARACTERS = { | |||
"Xavier", | |||
"Zayne", | |||
"Rafayel", | |||
"Sylus", | |||
"Caleb" | |||
} | |||
local SERVER_TIMEZONES = { | |||
asia = 8, | |||
europe = 2, | |||
america = -7 | |||
} | |||
local RESET_HOUR = 5 | |||
local BUFFER_HOURS = 48 | |||
-- ============================================================================ | |||
-- UTILITY FUNCTIONS | |||
-- ============================================================================ | |||
-- Split a delimited string, trim whitespace from each part | |||
local function splitAndTrim( str, sep ) | |||
local result = {} | |||
for part in str:gmatch( "[^" .. sep .. "]+" ) do | |||
local trimmed = part:match( "^%s*(.-)%s*$" ) | |||
if trimmed ~= "" then | |||
table.insert( result, trimmed ) | |||
end | |||
end | |||
return result | |||
end | |||
-- Resolve characters field: expands "All" to full roster | |||
local function resolveCharacters( raw ) | |||
if not raw or raw == "" then return {} end | |||
local trimmed = raw:match( "^%s*(.-)%s*$" ) | |||
if trimmed == "All" then return ALL_CHARACTERS end | |||
return splitAndTrim( raw, ";" ) | |||
end | |||
function p.formatDate( isoString ) | |||
if not isoString or isoString == "" then return "" end | |||
local year = tonumber( isoString:sub( 1, 4 ) ) | |||
local month = tonumber( isoString:sub( 6, 7 ) ) | |||
local day = tonumber( isoString:sub( 9, 10 ) ) | |||
if not year or not month or not day then return "" end | |||
local monthNames = { | |||
"January", "February", "March", "April", "May", "June", | |||
"July", "August", "September", "October", "November", "December" | |||
} | |||
return monthNames[month] .. " " .. day .. ", " .. year | |||
end | |||
function p.ordinal( n ) | |||
n = tonumber( n ) | |||
if n % 100 >= 11 and n % 100 <= 13 then return n .. "th" end | |||
local suffixes = { [1] = "st", [2] = "nd", [3] = "rd" } | |||
return n .. ( suffixes[n % 10] or "th" ) | |||
end | |||
function p.formatDateOrdinal( isoString ) | |||
if not isoString or isoString == "" then return "" end | |||
local year = tonumber( isoString:sub( 1, 4 ) ) | |||
local month = tonumber( isoString:sub( 6, 7 ) ) | |||
local day = tonumber( isoString:sub( 9, 10 ) ) | |||
if not year or not month or not day then return "" end | |||
local monthNames = { | |||
"January", "February", "March", "April", "May", "June", | |||
"July", "August", "September", "October", "November", "December" | |||
} | |||
return monthNames[month] .. " " .. p.ordinal( day ) .. ", " .. year | |||
end | |||
-- ============================================================================ | |||
-- TIMESTAMP PARSING | |||
-- ============================================================================ | |||
function p.parseTimestamp( isoString ) | |||
if not isoString or isoString == "" then return nil end | |||
local year, month, day, hour, min, sec | |||
if #isoString == 10 then | |||
year = tonumber( isoString:sub( 1, 4 ) ) | |||
month = tonumber( isoString:sub( 6, 7 ) ) | |||
day = tonumber( isoString:sub( 9, 10 ) ) | |||
hour, min, sec = RESET_HOUR, 0, 0 | |||
else | |||
year = tonumber( isoString:sub( 1, 4 ) ) | |||
month = tonumber( isoString:sub( 6, 7 ) ) | |||
day = tonumber( isoString:sub( 9, 10 ) ) | |||
hour = tonumber( isoString:sub( 12, 13 ) ) or 0 | |||
min = tonumber( isoString:sub( 15, 16 ) ) or 0 | |||
sec = tonumber( isoString:sub( 18, 19 ) ) or 0 | |||
end | |||
if not year or not month or not day then return nil end | |||
local baseTime = os.time( { year = year, month = month, day = day, | |||
hour = hour, min = min, sec = sec } ) | |||
return { | |||
asia = baseTime - ( SERVER_TIMEZONES.asia * 3600 ), | |||
europe = baseTime - ( SERVER_TIMEZONES.europe * 3600 ), | |||
america = baseTime - ( SERVER_TIMEZONES.america * 3600 ) | |||
} | |||
end | |||
-- ============================================================================ | |||
-- FILTERING & SORTING | |||
-- ============================================================================ | |||
function p.filterCurrentEvents( events ) | |||
local now = os.time() | |||
local buffer = BUFFER_HOURS * 3600 | |||
local valid = {} | |||
for _, event in ipairs( events ) do | |||
local endDate = event["end"] | |||
if endDate and endDate ~= "" then | |||
local year = tonumber( endDate:sub( 1, 4 ) ) | |||
local month = tonumber( endDate:sub( 6, 7 ) ) | |||
local day = tonumber( endDate:sub( 9, 10 ) ) | |||
if year and month and day then | |||
local endTime = os.time( { year = year, month = month, day = day, | |||
hour = 23, min = 59, sec = 59 } ) + buffer | |||
if endTime > now then | |||
table.insert( valid, event ) | |||
end | |||
else | |||
table.insert( valid, event ) | |||
end | |||
else | |||
table.insert( valid, event ) | |||
end | |||
end | |||
return { asia = valid, europe = valid, america = valid } | |||
end | |||
function p.sortEventsByStart( events, server, descending ) | |||
table.sort( events, function( a, b ) | |||
local aT = p.parseTimestamp( a.start ) | |||
local bT = p.parseTimestamp( b.start ) | |||
if not aT then return false end | |||
if not bT then return true end | |||
local aS = aT[server] | |||
local bS = bT[server] | |||
if not aS then return false end | |||
if not bS then return true end | |||
return descending and ( aS > bS ) or ( aS < bS ) | |||
end ) | |||
return events | |||
end | |||
-- ============================================================================ | |||
-- BUCKET DATA ACCESS | |||
-- ============================================================================ | |||
local function queryEvents( filters ) | |||
local q = bucket("events") | |||
.select( "name", "label", "type", "subtype", "image", | |||
"start", "end", "characters", "reward_memory", "description" ) | |||
.orderBy( "start", "desc" ) | |||
if filters then | |||
for _, condition in ipairs( filters ) do | |||
if | q = q.where( condition ) | ||
for | |||
end | end | ||
end | end | ||
return q.run() | |||
end | |||
-- ============================================================================ | |||
-- BUCKET WRITE | |||
-- ============================================================================ | |||
function p.store( frame ) | |||
local args = frame.args | |||
local characters = resolveCharacters( args.characters ) | |||
bucket("events").put({ | bucket("events").put({ | ||
name | name = args.name or "", | ||
label | label = args.label or "", | ||
type | type = args.type or "", | ||
image | subtype = args.subtype or "", | ||
start | image = args.image or "", | ||
["end"] | start = args.start or "", | ||
characters | ["end"] = args["end"] or "", | ||
description = args.description or "" | characters = characters, | ||
reward_memory = args.reward_memory or "", | |||
description = args.description or "" | |||
}) | }) | ||
| Line 27: | Line 199: | ||
end | end | ||
-- | -- ============================================================================ | ||
-- CARD RENDERING | |||
local | -- ============================================================================ | ||
local | |||
local | function p.renderEventCard( event, servers ) | ||
local | local name = event.name or "" | ||
local eventType = event.type or "story" | |||
local image = event.image or ( name .. "_Banner.png" ) | |||
local label = event.label or name | |||
local startTime = event.start or "" | |||
local endTime = event["end"] or "" | |||
local description = event.description or "" | |||
local card = '<div class="event-card-container event-item" data-type="' .. eventType | |||
.. '" data-servers="' .. ( servers or "asia,europe,america" ) .. '">\n' | |||
card = card .. '<div class="event-card-header" style="z-index: 3;">\n' | |||
card = card .. '<div class="event-duration"><b><span class="js-start-date"></span>' | |||
.. ' - <span class="js-end-date"></span></b>\n' | |||
card = card .. '</div><span class="event-countdown" data-start="' .. startTime | |||
.. '" data-end="' .. endTime .. '"></span>\n' | |||
card = card .. '</div>\n' | |||
card = card .. '<div class="event-card-body">\n' | |||
card = card .. '<div class="js-image-container" style="display:none;">[[File:' | |||
.. image .. '|link=]]</div>\n' | |||
card = card .. '<div style="z-index: 3;">\n' | |||
card = card .. '<div class="event-title">[[' .. name .. '|' .. label .. ']]\n' | |||
card = card .. '</div>\n' | |||
card = card .. '<div class="event-description"><small>' .. description .. '</small>\n' | |||
card = card .. '</div>\n' | |||
card = card .. '</div>\n' | |||
card = card .. '</div>\n' | |||
card = card .. '</div>\n' | |||
return card | |||
end | |||
-- ============================================================================ | |||
-- PUBLIC RENDER FUNCTIONS | |||
-- ============================================================================ | |||
function p.renderCurrentEvents( frame ) | |||
local results = queryEvents() | |||
if not results or #results == 0 then | |||
return '<div class="notice">No events data available.</div>' | |||
end | |||
local filteredByServer = p.filterCurrentEvents( results ) | |||
local allEvents = {} | |||
local eventServers = {} | |||
for server, serverEvents in pairs( filteredByServer ) do | |||
for _, event in ipairs( serverEvents ) do | |||
local key = event.name | |||
if not eventServers[key] then | |||
eventServers[key] = {} | |||
table.insert( allEvents, event ) | |||
end | |||
table.insert( eventServers[key], server ) | |||
end | |||
end | |||
if #allEvents == 0 then | |||
return '<div class="notice">No current or upcoming events.</div>' | |||
end | |||
local | table.sort( allEvents, function( a, b ) | ||
. | local aT = p.parseTimestamp( a["end"] ) | ||
. | local bT = p.parseTimestamp( b["end"] ) | ||
if not aT then return false end | |||
if not bT then return true end | |||
local aMin = math.min( aT.asia or math.huge, aT.europe or math.huge, aT.america or math.huge ) | |||
local bMin = math.min( bT.asia or math.huge, bT.europe or math.huge, bT.america or math.huge ) | |||
return aMin < bMin | |||
end ) | |||
local output = '<div class="event-gallery-wrapper">\n<div class="event-gallery" data-server-filter="true">\n' | |||
for _, event in ipairs( allEvents ) do | |||
local servers = table.concat( eventServers[event.name], "," ) | |||
output = output .. p.renderEventCard( event, servers ) | |||
end | end | ||
output = output .. '</div>\n</div>' | |||
if | return output | ||
end | |||
function p.getEventsByType( frame ) | |||
local args = getArgs( frame ) | |||
local filterType = args[1] or args.type | |||
if not filterType then | |||
return '<div class="error">No event type provided</div>' | |||
end | end | ||
filterType = mw.text.trim( filterType ) | |||
local results = | local results = queryEvents( { { "type", filterType } } ) | ||
if not results or #results == 0 then | if not results or #results == 0 then | ||
return "No events found. | return '<div class="notice">No current ' .. mw.text.encode( filterType ) .. ' events found.</div>' | ||
end | end | ||
local filteredByServer = p.filterCurrentEvents( results ) | |||
local allEvents = {} | |||
local eventServers = {} | |||
for _, | |||
if | for server, serverEvents in pairs( filteredByServer ) do | ||
table.insert( | for _, event in ipairs( serverEvents ) do | ||
local key = event.name | |||
if not eventServers[key] then | |||
eventServers[key] = {} | |||
table.insert( allEvents, event ) | |||
end | end | ||
table.insert( eventServers[key], server ) | |||
end | end | ||
end | end | ||
-- | if #allEvents == 0 then | ||
local | return '<div class="notice">No current ' .. mw.text.encode( filterType ) .. ' events found.</div>' | ||
end | |||
local output = '<div class="event-gallery-wrapper">\n<div class="event-gallery" data-server-filter="true">\n' | |||
for _, event in ipairs( allEvents ) do | |||
local servers = table.concat( eventServers[event.name], "," ) | |||
output = output .. p.renderEventCard( event, servers ) | |||
end | |||
output = output .. '</div>\n</div>' | |||
return output | |||
end | |||
function p.render10Days( frame ) | |||
local results = queryEvents( { { "name", "10 Days With You" }, { "type", "checkin" } } ) | |||
if not results or #results == 0 then | |||
return '<div class="notice">No 10 Days With You events found.</div>' | |||
end | |||
p.sortEventsByStart( results, "america", false ) | |||
local output = '{| class="wikitable tendays" style="margin:auto"\n' | |||
output = output .. '|-\n! Title !! Memory !! Duration\n' | |||
for _, event in ipairs( results ) do | |||
local banner = event.image or ( event.name .. "_Banner.png" ) | |||
local startStr = p.formatDateOrdinal( event.start ) | |||
local endStr = p.formatDateOrdinal( event["end"] ) | |||
local duration = startStr .. " - " .. endStr | |||
local memory = event.reward_memory or "" | |||
local memoryCell = "" | |||
if memory ~= "" then | |||
memoryCell = frame:expandTemplate{ title = "Memorybox", args = { memory = memory } } | |||
else | |||
memoryCell = "''No memory listed''" | |||
end | |||
local titleCell = "[[File:" .. banner .. "|300px]]" | |||
if memory ~= "" then | |||
titleCell = titleCell .. "<br>[[" .. memory .. "]]" | |||
end | |||
output = output .. "|-\n" | |||
output = output .. "| style=\"width: 40%\" | " .. titleCell .. "\n" | |||
output = output .. "| style=\"width: 25%\" | " .. memoryCell .. "\n" | |||
output = output .. "| style=\"width: 35%\" | " .. duration .. "\n" | |||
end | |||
output = output .. "|}" | |||
return output | |||
end | |||
function p.renderHeartfeltGift( frame ) | |||
local results = queryEvents( { { "name", "Heartfelt Gift" }, { "type", "checkin" } } ) | |||
if not results or #results == 0 then | |||
return '<div class="notice">No Heartfelt Gift events found.</div>' | |||
end | |||
p.sortEventsByStart( results, "america", false ) | |||
local output = '{| class="wikitable tendays" style="margin:auto"\n' | |||
output = output .. '|-\n! Title !! Memory !! Duration\n' | |||
for _, event in ipairs( results ) do | |||
local banner = event.image or ( event.name .. "_Banner.png" ) | |||
local startStr = p.formatDateOrdinal( event.start ) | |||
local endStr = p.formatDateOrdinal( event["end"] ) | |||
local duration = startStr .. " - " .. endStr | |||
local memory = event.reward_memory or "" | |||
local memoryCell = "" | |||
if memory ~= "" then | |||
memoryCell = frame:expandTemplate{ title = "Memorybox", args = { memory = memory } } | |||
if | else | ||
memoryCell = "''No memory listed''" | |||
end | end | ||
local | local titleCell = "[[File:" .. banner .. "|300px]]" | ||
if | if memory ~= "" then | ||
titleCell = titleCell .. "<br>[[" .. memory .. "]]" | |||
end | end | ||
local label = row.label or row.name or "" | output = output .. "|-\n" | ||
output = output .. "| style=\"width: 40%\" | " .. titleCell .. "\n" | |||
output = output .. "| style=\"width: 25%\" | " .. memoryCell .. "\n" | |||
output = output .. "| style=\"width: 35%\" | " .. duration .. "\n" | |||
end | |||
output = output .. "|}" | |||
return output | |||
end | |||
function p.list( frame ) | |||
local results = queryEvents() | |||
if not results or #results == 0 then | |||
return "No events found." | |||
end | |||
local out = {} | |||
table.insert( out, '{| class="wikitable sortable"' ) | |||
table.insert( out, '! Name !! Type !! Subtype !! Start !! End !! Description' ) | |||
for _, row in ipairs( results ) do | |||
local label = ( row.label and row.label ~= "" ) and row.label or row.name | |||
local name = ( row.name and row.name ~= "" ) and row.name or "" | |||
local link | |||
if name ~= "" then | |||
link = ( label ~= name ) and "[[" .. name .. "|" .. label .. "]]" | |||
or "[[" .. name .. "]]" | |||
else | |||
link = label | |||
end | |||
table.insert(out, "|-") | table.insert( out, "|-" ) | ||
table.insert(out, string.format( | table.insert( out, string.format( | ||
"| %s || %s || %s || %s || %s || %s", | "| %s || %s || %s || %s || %s || %s", | ||
link, | |||
row.type, | row.type or "", | ||
row.subtype or "", | |||
row.start, | row.start or "", | ||
row["end"], | row["end"] or "", | ||
row.description or "" | row.description or "" | ||
)) | )) | ||
end | end | ||
table.insert(out, "|}") | table.insert( out, "|}" ) | ||
return table.concat(out, "\n") | return table.concat( out, "\n" ) | ||
end | end | ||
return p | return p | ||
Latest revision as of 01:37, 25 April 2026
Documentation for this module may be created at Module:Events/doc
local p = {}
local getArgs = require('Module:Arguments').getArgs
-- ============================================================================
-- CONFIGURATION
-- ============================================================================
local ALL_CHARACTERS = {
"Xavier",
"Zayne",
"Rafayel",
"Sylus",
"Caleb"
}
local SERVER_TIMEZONES = {
asia = 8,
europe = 2,
america = -7
}
local RESET_HOUR = 5
local BUFFER_HOURS = 48
-- ============================================================================
-- UTILITY FUNCTIONS
-- ============================================================================
-- Split a delimited string, trim whitespace from each part
local function splitAndTrim( str, sep )
local result = {}
for part in str:gmatch( "[^" .. sep .. "]+" ) do
local trimmed = part:match( "^%s*(.-)%s*$" )
if trimmed ~= "" then
table.insert( result, trimmed )
end
end
return result
end
-- Resolve characters field: expands "All" to full roster
local function resolveCharacters( raw )
if not raw or raw == "" then return {} end
local trimmed = raw:match( "^%s*(.-)%s*$" )
if trimmed == "All" then return ALL_CHARACTERS end
return splitAndTrim( raw, ";" )
end
function p.formatDate( isoString )
if not isoString or isoString == "" then return "" end
local year = tonumber( isoString:sub( 1, 4 ) )
local month = tonumber( isoString:sub( 6, 7 ) )
local day = tonumber( isoString:sub( 9, 10 ) )
if not year or not month or not day then return "" end
local monthNames = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
}
return monthNames[month] .. " " .. day .. ", " .. year
end
function p.ordinal( n )
n = tonumber( n )
if n % 100 >= 11 and n % 100 <= 13 then return n .. "th" end
local suffixes = { [1] = "st", [2] = "nd", [3] = "rd" }
return n .. ( suffixes[n % 10] or "th" )
end
function p.formatDateOrdinal( isoString )
if not isoString or isoString == "" then return "" end
local year = tonumber( isoString:sub( 1, 4 ) )
local month = tonumber( isoString:sub( 6, 7 ) )
local day = tonumber( isoString:sub( 9, 10 ) )
if not year or not month or not day then return "" end
local monthNames = {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
}
return monthNames[month] .. " " .. p.ordinal( day ) .. ", " .. year
end
-- ============================================================================
-- TIMESTAMP PARSING
-- ============================================================================
function p.parseTimestamp( isoString )
if not isoString or isoString == "" then return nil end
local year, month, day, hour, min, sec
if #isoString == 10 then
year = tonumber( isoString:sub( 1, 4 ) )
month = tonumber( isoString:sub( 6, 7 ) )
day = tonumber( isoString:sub( 9, 10 ) )
hour, min, sec = RESET_HOUR, 0, 0
else
year = tonumber( isoString:sub( 1, 4 ) )
month = tonumber( isoString:sub( 6, 7 ) )
day = tonumber( isoString:sub( 9, 10 ) )
hour = tonumber( isoString:sub( 12, 13 ) ) or 0
min = tonumber( isoString:sub( 15, 16 ) ) or 0
sec = tonumber( isoString:sub( 18, 19 ) ) or 0
end
if not year or not month or not day then return nil end
local baseTime = os.time( { year = year, month = month, day = day,
hour = hour, min = min, sec = sec } )
return {
asia = baseTime - ( SERVER_TIMEZONES.asia * 3600 ),
europe = baseTime - ( SERVER_TIMEZONES.europe * 3600 ),
america = baseTime - ( SERVER_TIMEZONES.america * 3600 )
}
end
-- ============================================================================
-- FILTERING & SORTING
-- ============================================================================
function p.filterCurrentEvents( events )
local now = os.time()
local buffer = BUFFER_HOURS * 3600
local valid = {}
for _, event in ipairs( events ) do
local endDate = event["end"]
if endDate and endDate ~= "" then
local year = tonumber( endDate:sub( 1, 4 ) )
local month = tonumber( endDate:sub( 6, 7 ) )
local day = tonumber( endDate:sub( 9, 10 ) )
if year and month and day then
local endTime = os.time( { year = year, month = month, day = day,
hour = 23, min = 59, sec = 59 } ) + buffer
if endTime > now then
table.insert( valid, event )
end
else
table.insert( valid, event )
end
else
table.insert( valid, event )
end
end
return { asia = valid, europe = valid, america = valid }
end
function p.sortEventsByStart( events, server, descending )
table.sort( events, function( a, b )
local aT = p.parseTimestamp( a.start )
local bT = p.parseTimestamp( b.start )
if not aT then return false end
if not bT then return true end
local aS = aT[server]
local bS = bT[server]
if not aS then return false end
if not bS then return true end
return descending and ( aS > bS ) or ( aS < bS )
end )
return events
end
-- ============================================================================
-- BUCKET DATA ACCESS
-- ============================================================================
local function queryEvents( filters )
local q = bucket("events")
.select( "name", "label", "type", "subtype", "image",
"start", "end", "characters", "reward_memory", "description" )
.orderBy( "start", "desc" )
if filters then
for _, condition in ipairs( filters ) do
q = q.where( condition )
end
end
return q.run()
end
-- ============================================================================
-- BUCKET WRITE
-- ============================================================================
function p.store( frame )
local args = frame.args
local characters = resolveCharacters( args.characters )
bucket("events").put({
name = args.name or "",
label = args.label or "",
type = args.type or "",
subtype = args.subtype or "",
image = args.image or "",
start = args.start or "",
["end"] = args["end"] or "",
characters = characters,
reward_memory = args.reward_memory or "",
description = args.description or ""
})
return ""
end
-- ============================================================================
-- CARD RENDERING
-- ============================================================================
function p.renderEventCard( event, servers )
local name = event.name or ""
local eventType = event.type or "story"
local image = event.image or ( name .. "_Banner.png" )
local label = event.label or name
local startTime = event.start or ""
local endTime = event["end"] or ""
local description = event.description or ""
local card = '<div class="event-card-container event-item" data-type="' .. eventType
.. '" data-servers="' .. ( servers or "asia,europe,america" ) .. '">\n'
card = card .. '<div class="event-card-header" style="z-index: 3;">\n'
card = card .. '<div class="event-duration"><b><span class="js-start-date"></span>'
.. ' - <span class="js-end-date"></span></b>\n'
card = card .. '</div><span class="event-countdown" data-start="' .. startTime
.. '" data-end="' .. endTime .. '"></span>\n'
card = card .. '</div>\n'
card = card .. '<div class="event-card-body">\n'
card = card .. '<div class="js-image-container" style="display:none;">[[File:'
.. image .. '|link=]]</div>\n'
card = card .. '<div style="z-index: 3;">\n'
card = card .. '<div class="event-title">[[' .. name .. '|' .. label .. ']]\n'
card = card .. '</div>\n'
card = card .. '<div class="event-description"><small>' .. description .. '</small>\n'
card = card .. '</div>\n'
card = card .. '</div>\n'
card = card .. '</div>\n'
card = card .. '</div>\n'
return card
end
-- ============================================================================
-- PUBLIC RENDER FUNCTIONS
-- ============================================================================
function p.renderCurrentEvents( frame )
local results = queryEvents()
if not results or #results == 0 then
return '<div class="notice">No events data available.</div>'
end
local filteredByServer = p.filterCurrentEvents( results )
local allEvents = {}
local eventServers = {}
for server, serverEvents in pairs( filteredByServer ) do
for _, event in ipairs( serverEvents ) do
local key = event.name
if not eventServers[key] then
eventServers[key] = {}
table.insert( allEvents, event )
end
table.insert( eventServers[key], server )
end
end
if #allEvents == 0 then
return '<div class="notice">No current or upcoming events.</div>'
end
table.sort( allEvents, function( a, b )
local aT = p.parseTimestamp( a["end"] )
local bT = p.parseTimestamp( b["end"] )
if not aT then return false end
if not bT then return true end
local aMin = math.min( aT.asia or math.huge, aT.europe or math.huge, aT.america or math.huge )
local bMin = math.min( bT.asia or math.huge, bT.europe or math.huge, bT.america or math.huge )
return aMin < bMin
end )
local output = '<div class="event-gallery-wrapper">\n<div class="event-gallery" data-server-filter="true">\n'
for _, event in ipairs( allEvents ) do
local servers = table.concat( eventServers[event.name], "," )
output = output .. p.renderEventCard( event, servers )
end
output = output .. '</div>\n</div>'
return output
end
function p.getEventsByType( frame )
local args = getArgs( frame )
local filterType = args[1] or args.type
if not filterType then
return '<div class="error">No event type provided</div>'
end
filterType = mw.text.trim( filterType )
local results = queryEvents( { { "type", filterType } } )
if not results or #results == 0 then
return '<div class="notice">No current ' .. mw.text.encode( filterType ) .. ' events found.</div>'
end
local filteredByServer = p.filterCurrentEvents( results )
local allEvents = {}
local eventServers = {}
for server, serverEvents in pairs( filteredByServer ) do
for _, event in ipairs( serverEvents ) do
local key = event.name
if not eventServers[key] then
eventServers[key] = {}
table.insert( allEvents, event )
end
table.insert( eventServers[key], server )
end
end
if #allEvents == 0 then
return '<div class="notice">No current ' .. mw.text.encode( filterType ) .. ' events found.</div>'
end
local output = '<div class="event-gallery-wrapper">\n<div class="event-gallery" data-server-filter="true">\n'
for _, event in ipairs( allEvents ) do
local servers = table.concat( eventServers[event.name], "," )
output = output .. p.renderEventCard( event, servers )
end
output = output .. '</div>\n</div>'
return output
end
function p.render10Days( frame )
local results = queryEvents( { { "name", "10 Days With You" }, { "type", "checkin" } } )
if not results or #results == 0 then
return '<div class="notice">No 10 Days With You events found.</div>'
end
p.sortEventsByStart( results, "america", false )
local output = '{| class="wikitable tendays" style="margin:auto"\n'
output = output .. '|-\n! Title !! Memory !! Duration\n'
for _, event in ipairs( results ) do
local banner = event.image or ( event.name .. "_Banner.png" )
local startStr = p.formatDateOrdinal( event.start )
local endStr = p.formatDateOrdinal( event["end"] )
local duration = startStr .. " - " .. endStr
local memory = event.reward_memory or ""
local memoryCell = ""
if memory ~= "" then
memoryCell = frame:expandTemplate{ title = "Memorybox", args = { memory = memory } }
else
memoryCell = "''No memory listed''"
end
local titleCell = "[[File:" .. banner .. "|300px]]"
if memory ~= "" then
titleCell = titleCell .. "<br>[[" .. memory .. "]]"
end
output = output .. "|-\n"
output = output .. "| style=\"width: 40%\" | " .. titleCell .. "\n"
output = output .. "| style=\"width: 25%\" | " .. memoryCell .. "\n"
output = output .. "| style=\"width: 35%\" | " .. duration .. "\n"
end
output = output .. "|}"
return output
end
function p.renderHeartfeltGift( frame )
local results = queryEvents( { { "name", "Heartfelt Gift" }, { "type", "checkin" } } )
if not results or #results == 0 then
return '<div class="notice">No Heartfelt Gift events found.</div>'
end
p.sortEventsByStart( results, "america", false )
local output = '{| class="wikitable tendays" style="margin:auto"\n'
output = output .. '|-\n! Title !! Memory !! Duration\n'
for _, event in ipairs( results ) do
local banner = event.image or ( event.name .. "_Banner.png" )
local startStr = p.formatDateOrdinal( event.start )
local endStr = p.formatDateOrdinal( event["end"] )
local duration = startStr .. " - " .. endStr
local memory = event.reward_memory or ""
local memoryCell = ""
if memory ~= "" then
memoryCell = frame:expandTemplate{ title = "Memorybox", args = { memory = memory } }
else
memoryCell = "''No memory listed''"
end
local titleCell = "[[File:" .. banner .. "|300px]]"
if memory ~= "" then
titleCell = titleCell .. "<br>[[" .. memory .. "]]"
end
output = output .. "|-\n"
output = output .. "| style=\"width: 40%\" | " .. titleCell .. "\n"
output = output .. "| style=\"width: 25%\" | " .. memoryCell .. "\n"
output = output .. "| style=\"width: 35%\" | " .. duration .. "\n"
end
output = output .. "|}"
return output
end
function p.list( frame )
local results = queryEvents()
if not results or #results == 0 then
return "No events found."
end
local out = {}
table.insert( out, '{| class="wikitable sortable"' )
table.insert( out, '! Name !! Type !! Subtype !! Start !! End !! Description' )
for _, row in ipairs( results ) do
local label = ( row.label and row.label ~= "" ) and row.label or row.name
local name = ( row.name and row.name ~= "" ) and row.name or ""
local link
if name ~= "" then
link = ( label ~= name ) and "[[" .. name .. "|" .. label .. "]]"
or "[[" .. name .. "]]"
else
link = label
end
table.insert( out, "|-" )
table.insert( out, string.format(
"| %s || %s || %s || %s || %s || %s",
link,
row.type or "",
row.subtype or "",
row.start or "",
row["end"] or "",
row.description or ""
))
end
table.insert( out, "|}" )
return table.concat( out, "\n" )
end
return p