Module:ScheduleList
Documentation for this module may be created at Module:ScheduleList/doc
local p = {}
-- Utility function: Check if a year is a leap year
local function is_leap_year(year)
return (year % 4 == 0 and year % 100 ~= 0) or (year % 400 == 0)
end
-- Utility function: Calculate the number of days in a month
local function days_in_month(month, leap_year)
local days = {31, leap_year and 29 or 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
return days[month]
end
-- Utility function: Convert `mmdd` input to `Month Day` format
local function format_date(mmdd)
local months = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}
local month = tonumber(string.sub(mmdd, 1, 2)) -- First two digits are the month
local day = tonumber(string.sub(mmdd, 3, 4)) -- Last two digits are the day
return string.format("%s %d", months[month], day)
end
-- Utility function: Calculate the next date
local function get_next_date(mmdd, leap_year)
local month = tonumber(string.sub(mmdd, 1, 2))
local day = tonumber(string.sub(mmdd, 3, 4))
local days_in_current_month = days_in_month(month, leap_year)
if day == days_in_current_month then
day = 1
month = month + 1
if month > 12 then
month = 1
end
else
day = day + 1
end
return string.format("%02d%02d", month, day) -- Return in mmdd format
end
-- Utility function: Get the weekday in common English abbreviations
local function get_weekday(weekday)
local weekdays = {"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"}
return weekdays[(weekday - 1) % 7 + 1]
end
-- Format date line
local function format_date_line(frame, date, time, week, title, css_class)
local formatted_date = format_date(date)
-- Set default title to "OFFLINE" if the title is empty
if not title or title == "" then
title = "OFFLINE"
end
local schedule_output
if title == "OFFLINE" then
css_class = (css_class and css_class .. " " or "") .. "offline" -- Add "offline" class if title is OFFLINE
schedule_output = frame:expandTemplate{
title = "ScheduleList/date",
args = {formatted_date, "", week, title} -- Time empty, title as "OFFLINE"
}
else
css_class = (css_class and css_class .. " " or "") .. "online" -- Add "online" class if title exists
time = time or "19:00" -- Default time is "19:00"
schedule_output = frame:expandTemplate{
title = "ScheduleList/date",
args = {formatted_date, time .. " (GMT)", week, title} -- Time and title displayed normally
}
end
-- Build HTML output
return string.format(
'<li class="%s" style="display: flex;">' ..
'<div class="datetime">%s</div>' ..
'</li>',
css_class, schedule_output
)
end
-- Main function
function p.main(frame)
local args = frame:getParent().args
-- Get initial parameters
local date = args.date -- Input date in `mmdd` format
local week = tonumber(args.week) -- Input weekday (1~7)
local leap_year = args.leap_year == "yes" -- Leap year check
-- Return error messages if required parameters are missing
if not date then return "Please provide an initial date (date parameter in mmdd format)!" end
if not week or week < 1 or week > 7 then return "Please provide a valid initial weekday (week parameter, 1~7)!" end
-- Initialize result table
local result = {}
local current_date = date
local current_weekday = week
-- Generate 7 rows in a loop
for i = 1, 7 do
local title = args["title" .. i] -- Title for each row
local time = args["time" .. i] -- Time for each row (optional)
local css_class = args["class" .. i] -- CSS class for each row
local week_day = get_weekday(current_weekday) -- Calculate weekday
-- Format each row
table.insert(result, format_date_line(frame, current_date, time, week_day, title, css_class))
-- Update date and weekday
current_date = get_next_date(current_date, leap_year)
current_weekday = current_weekday + 1
end
-- Wrap in <ul> and return as the result
return '<ul class="schedule-list">' .. table.concat(result, "\n") .. '</ul>'
end
return p