Module:Sandbox/Tokoko/Calendar

require('strict')

local p = {} local root = {}

local function addRow(row) table.insert(root, row) end

local function isLeapYear(year) return year % 4 == 0 and (year % 100 ~= 0 or year % 400 == 0) end

local function getDaysInMonth(month, year) return month == 2 and isLeapYear(year) and 29 or ("\31\28\31\30\31\30\31\31\30\31\30\31"):byte(month) end

local function getMonthNumber(m) if tonumber(m) ~= nil then return tonumber(m) elseif m == "current" then return tonumber(os.date("%m")) elseif m == "next" then return tonumber(os.date("%m")) % 12 + 1 elseif m == "last" then return (tonumber(os.date("%m")) - 2) % 12 + 1 else return 1 end end

local function applyDefaultValue(inputValue, defaultValue) return (inputValue and inputValue ~= "") and inputValue or defaultValue end

local function getWeekdays(format) if format == "Mon1st" then return {"Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} elseif format == "iso" then return {"Wk", "Mo", "Tu", "We", "Th", "Fr", "Sa", "Su"} else return {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"} end end

local function getIsoWeekNumber(year, month, day) local daysFromStart = os.difftime(os.time{year= year, month=month, day=day}, os.time{year=year, month=1, day=1}) / 86400 local daysUntilEnd = os.difftime(os.time{year= year + 1, month=1, day=1}, os.time{year=year, month=month, day=day}) / 86400 local firstWeekday = tonumber(os.date("%w",os.time{year=year, month=month, day=1})) local nextFirstWeekday = tonumber(os.date("%w",os.time{year=year+1, month=month, day=1})) if daysUntilEnd < 4 and nextFirstWeekday >= 4 then return 1 end local daysFromFirstMonday = daysFromStart	- (8 - firstWeekday) local iso = math.floor(daysFromFirstMonday / 7) + 2 - (firstWeekday > 5 and 1 or 0) return iso == 0 and getIsoWeekNumber(year - 1, 12, 26) or iso end

local function make_link(text, flag, pref, suff) return flag and "" .. text .. "" or text end

local function format_date(date) return date < 10 and " " .. date or date end

local function _calendar(frame, _monthNumber, full_mode, float) local monthNumber = _monthNumber local year = tonumber(applyDefaultValue(frame.args.year,os.date("%Y"))) local month = os.date("%B", os.time{year=year, month=monthNumber, day=1}) local show_year = applyDefaultValue(frame.args.show_year,"on") local format = applyDefaultValue(frame.args.format,"Sun1st") --format = "iso" local colspan = (format == "iso" and 8 or 7) local prevnext = applyDefaultValue(frame.args.prevnext == "on", false) local end_note = applyDefaultValue(frame.args.EndNote, "") local colour = frame.args.colour local title_colour = applyDefaultValue(colour,frame.args.title_colour) local week_colour = applyDefaultValue(colour,frame.args.week_colour) local wknum_colour = frame.args.wknum_colour local lk = applyDefaultValue(frame.args.lk, "") local show_link_year = string.match(lk, "y") local show_link_month = string.match(lk, "m") local show_link_day = string.match(lk, "d") local lk_pref = frame.args.lk_pref local lk_suff = frame.args.lk_suff local lk_pref_d = applyDefaultValue(lk_pref,frame.args.lk_pref_d) local lk_suff_d = applyDefaultValue(lk_suff,frame.args.lk_suff_d) local lk_pref_m = applyDefaultValue(lk_pref,frame.args.lk_pref_m) local lk_suff_m = applyDefaultValue(lk_suff,frame.args.lk_suff_m) local lk_pref_mnext = frame.args.lk_pref_mnext local lk_pref_mprev = frame.args.lk_pref_mprev local lk_suff_mnext = frame.args.lk_suff_mnext local lk_suff_mprev = frame.args.lk_suff_mprev if full_mode and show_year == "on" then show_year = "with month" end -- calculate helper variables local prevMonth = os.date("%B", os.time{year=year, month=(monthNumber - 2) % 12 + 1, day=1}) local nextMonth = os.date("%B", os.time{year=year, month=monthNumber % 12 + 1, day=1}) local firstWeekday = tonumber(os.date("%w",os.time{year=year, month=monthNumber, day=1})) local daysInMonth = getDaysInMonth(monthNumber, year)

-- constuct title addRow("{| class=\"toccolours " .. float .. "\" style=\"text-align:center;\" cellpadding=2 cellspacing=0\n") addRow("|- class=\"navbox-title\"" .. " style=\"background:" .. title_colour .. ";\"\n") local title_colspan = (prevnext and colspan - 2 or colspan) local title = make_link(month .. (show_year == "with month" and " " .. year or ""), show_link_month, lk_pref_m, lk_suff_m) local title_row = "|colspan=\"" .. title_colspan .. "\"|'''" .. title .. "'''\n" if prevnext then addRow("| << \n" .. title_row .. "|  >> \n") else addRow(title_row) end

-- construct weekdays addRow("|- class=\"navbox-title\"" .. " style=\"background:" .. week_colour .. ";\"\n") for i, wd in ipairs(getWeekdays(format)) do addRow("|" .. wd .. "\n") end addRow("|-\n")

-- construct dates local daysToMiss = firstWeekday - ((format == "Mon1st" or format == "iso") and 1 or 0) local date = - daysToMiss + 1 local num_rows = full_mode and 6 or math.ceil((daysInMonth + daysToMiss) / 7) for i = 1, num_rows * colspan do		local lastColumn = i % colspan == 0 local firstColumn = i % colspan == 1 if format == "iso" and firstColumn then addRow("| class=\"navbox-abovebelow\" style=\"background:" .. wknum_colour .. ";\"|" .. getIsoWeekNumber(year, monthNumber, date) .. "\n") elseif date > 0 and date <= daysInMonth then addRow("|" .. make_link(format_date(date), show_link_day, lk_pref_d .. month .. " ", lk_suff_d) .. "\n") date = date + 1 else addRow("| \n") date = date + 1 end if(lastColumn) then addRow("|-\n") end end if end_note ~= "" then addRow("|- class=\"navbox-title\" \n") addRow("|colspan=\"" .. colspan .."\"|" .. end_note .. "\n") end if show_year == "on" then addRow("|- class=\"navbox-title\"" .. " style=\"background:" .. title_colour .. ";\"\n") addRow("|colspan=\"" .. colspan .. "\"|" .. make_link(year, show_link_year, "", "") .. "\n") end addRow("|}") end

function p.main(frame)

local _month = frame.args.month local full_calendar = not (_month and _month ~= "") local year = tonumber(applyDefaultValue(frame.args.year,os.date("%Y"))) local title = applyDefaultValue(frame.args.title,"") local col = applyDefaultValue(frame.args.col,4) local row = frame.args.row local float = "float" .. applyDefaultValue(frame.args.float,"left") if full_calendar then addRow("{| class=\"" .. float .. "\" style=none\n") addRow("! colspan=" .. col .. " style=\"text-align:center; font-size:larger;\" | " .. title .. " " .. year .. "\n") for i=1, 12 do 			if (i - 1) % col == 0 then addRow("|- style=\"vertical-align: top;\"\n") end addRow("|\n") _calendar(frame, i, true, "") addRow("\n") end addRow("|}") else _calendar(frame, getMonthNumber(frame.args.month), false, float) end

--return " " .. table.concat(root) .. " \n" .. return table.concat(root) end

return p