Module:Calendar

From Angelina Jordan Wiki
Revision as of 22:01, 27 September 2025 by Most2dot0 (talk | contribs) (shorter weekday abbreviations)

Documentation for this module may be created at Module:Calendar/doc

local p = {}

local function trim(s)
    if not s then return nil end
    return (tostring(s):gsub("^%s*(.-)%s*$", "%1"))
end

local function escAttr(s)
    if not s then return "" end
    return tostring(s):gsub("&","&amp;"):gsub('"',"&quot;"):gsub("<","&lt;"):gsub(">","&gt;")
end

local function extractDay(dateStr)
    if not dateStr then return nil end
    local y, m, d = tostring(dateStr):match("^(%d%d%d%d)%-(%d%d)%-(%d%d)")
    if d then return tonumber(d) end
    return nil
end

function p.month(frame)
    local args = frame.args or (frame.getParent and frame:getParent().args) or {}
    local year = tonumber(trim(args.year))
    local month = tonumber(trim(args.month))
    if not year or not month then
        return "Error: module requires numeric |year= and |month=."
    end
    if month < 1 or month > 12 then
        return "Error: |month must be between 1 and 12."
    end

    local tableName = trim(args.table) or "DatedEvents"
    local dateField = trim(args.datefield) or "Date"
    local urlField  = trim(args.urlfield)  or "Link"

    local daysInMonth = tonumber(os.date("*t", os.time{year=year, month=month+1, day=0}).day)
    local firstWday   = tonumber(os.date("*t", os.time{year=year, month=month, day=1}).wday) -- correct ordering

    local out = {}

    -- query Cargo (if available)
    local events = {}
    if mw and mw.ext and mw.ext.cargo and mw.ext.cargo.query then
        local startDate = string.format("%04d-%02d-01", year, month)
        local endDate   = string.format("%04d-%02d-%02d", year, month, daysInMonth)
        local where = string.format("%s >= '%s' AND %s <= '%s'", dateField, startDate, dateField, endDate)
        local ok, results = pcall(mw.ext.cargo.query, tableName, dateField .. "," .. urlField, { where = where, limit = 1000 })
        if ok and results then
            for _, row in ipairs(results) do
                local dateVal = row[dateField] or row[1]
                local linkVal = row[urlField]  or row[2]
                local di = extractDay(dateVal)
-- 				table.insert(out, string.format("|- \n| %s || %s", dateVal or "nil", linkVal or "nil"))                end
                if di and linkVal then
                    events[di] = events[di] or {}
                    table.insert(events[di], tostring(linkVal))
                end
            end
        end
    end

    -- build calendar rows safely (cells per row)
    table.insert(out, '{| class="wikitable calendar" <table class="wikitable" style="font-size:80%; text-align:center; float:right; clear:right; margin-left:.2em;">')
    table.insert(out, '!Su !!Mo !!Tu !!We !!Th !!Fr !!Sa')

    local day = 1
    while day <= daysInMonth do
        local cells = {}
        for col = 1, 7 do
            if day == 1 and col < firstWday then
                table.insert(cells, " ")
            elseif day <= daysInMonth then
                if events[day] and #events[day] > 0 then
                    local firstLink = events[day][1]
                    local tip = escAttr(table.concat(events[day], ", "))
                    -- put attributes before the cell content
                    table.insert(cells, string.format("[[%s|'''%d''']]", firstLink, day))
                else
                    table.insert(cells, tostring(day))
                end
                day = day + 1
            else
                table.insert(cells, " ")
            end
        end
        table.insert(out, "|-")
        table.insert(out, "| " .. table.concat(cells, " || "))
    end

    table.insert(out, "|}")
    return table.concat(out, "\n")
end

-- test function
function p.test(frame)
    local tableName = "DatedEvents"
    local dateField = "Date"
    local urlField  = "Link"
    local year, month = 2014, 3
    local daysInMonth = tonumber(os.date("*t", os.time{year=year, month=month+1, day=0}).day)
    local startDate = string.format("%04d-%02d-01", year, month)
    local endDate   = string.format("%04d-%02d-%02d", year, month, daysInMonth)

    if not (mw and mw.ext and mw.ext.cargo and mw.ext.cargo.query) then
        return "Cargo extension not available."
    end

    local results = mw.ext.cargo.query(
        tableName,
        dateField .. "," .. urlField,
        { where = string.format("%s >= '%s' AND %s <= '%s'", dateField, startDate, dateField, endDate), limit = 50 }
    )

    -- log to server logs
    mw.logObject(results, "Cargo results")

    -- also return readable text in wiki page
    local out = { "=== Debug Output ===" }
    for i, row in ipairs(results) do
        local dateVal = row[dateField]
        local linkVal = row[urlField]
        table.insert(out, string.format("* Row %d: Date=%s Link=%s Day=%s", i, tostring(dateVal), tostring(linkVal), tostring(extractDay(dateVal))))
    end
    return table.concat(out, "\n")
end
return p