Module:ChapterList

From Candypedia

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

-- Module:ChapterList (enhanced)
-- Builds a sortable chapter table with volume headers, "Not yet in print",
-- and book‑exclusive chapters. All metadata is pulled from Module:ChapterNavbox.

local p = {}

---------------------------------------------------------------------
-- helpers
---------------------------------------------------------------------
local function formatDate(iso)
    local y, m, d = iso:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
    if not y then return iso or '' end
    return tonumber(m) .. "/" .. tonumber(d) .. "/" .. y:sub(3, 4)
end

-- numeric value of a chapter number (handles decimals)
local function numVal(n)
    return tonumber(n) or 0
end

---------------------------------------------------------------------
-- pull data
---------------------------------------------------------------------
local nav = require('Module:ChapterNavbox') -- expects .volumes and .bookExclusiveChapters
local volumes = nav.volumes or {}
local bookExclusive = nav.bookExclusiveChapters or {}

-- read the raw wikitext list (Template:ChapterList)
local tplTitle = mw.title.new('Template:ChapterList')
local raw = tplTitle and tplTitle:getContent() or ''

-- parse {{Chapter|number=…|title=…|date=…}}
local chapters = {}
for _, line in ipairs(mw.text.split(raw, "\n", true)) do
    local trimmed = mw.text.trim(line)
    if trimmed:find('^{{Chapter') then
        local inner = trimmed:match('^{{Chapter%s*(.+)}}$')
        if inner then
            if inner:sub(1,1) == '|' then inner = inner:sub(2) end
            local params = {}
            for part in inner:gmatch('[^|]+') do
                local k, v = part:match('^(%w+)%s*=%s*(.+)$')
                if k and v then params[k] = v end
            end
            if params.number and params.title and params.date then
                table.insert(chapters, params)
            end
        end
    end
end

-- sort chapters by numeric number
table.sort(chapters, function(a,b) return numVal(a.number) < numVal(b.number) end)

---------------------------------------------------------------------
-- build table
---------------------------------------------------------------------
local function addHeaderRow(out, text, colspan)
    table.insert(out, '|-')
    table.insert(out, '! colspan="' .. (colspan or 3) .. '" | ' .. text)
end

function p.renderTable(frame)
    local out = {
        '{| class="wikitable sortable"',
        '! #',
        '! Title',
        '! Published'
    }

    -- iterate volumes in declared order
    local used = {} -- track chapters already emitted
    for _, vol in ipairs(volumes) do
        -- header with optional style
        local header = vol.name
        if vol.style and vol.style ~= '' then
            table.insert(out, '|-')
            table.insert(out, '! colspan="3" style="' .. vol.style .. '" | ' .. header)
        else
            addHeaderRow(out, header)
        end

        for _, ch in ipairs(chapters) do
            if not used[ch] then
                local n = numVal(ch.number)
                if n >= vol.start and n <= vol.end_ then
                    used[ch] = true
                    local isInter = tostring(ch.number):find('%.')
                    local dispNum = isInter and '' or ch.number
                    local dispTitle = isInter and ('Intermission: [[' .. ch.title .. ']]')
                                                  or ('[[' .. ch.title .. ']]')
                    table.insert(out, '|-')
                    table.insert(out, '| ' .. dispNum .. ' || ' .. dispTitle .. ' || ' .. formatDate(ch.date))
                end
            end
        end
    end

    -- Not yet in print header
    addHeaderRow(out, 'Not yet in print')
    for _, ch in ipairs(chapters) do
        if not used[ch] then
            local isInter = tostring(ch.number):find('%.')
            local dispNum = isInter and '' or ch.number
            local dispTitle = isInter and ('Intermission: [[' .. ch.title .. ']]')
                                              or ('[[' .. ch.title .. ']]')
            table.insert(out, '|-')
            table.insert(out, '| ' .. dispNum .. ' || ' .. dispTitle .. ' || ' .. formatDate(ch.date))
            used[ch] = true
        end
    end

    -- Book‑exclusive header
    if #bookExclusive > 0 then
        addHeaderRow(out, 'Book‑exclusive')
        for _, be in ipairs(bookExclusive) do
            local link = be.link or be.title:gsub(' ', '_')
            table.insert(out, '|-')
            table.insert(out, '|  || [[' .. link .. '|' .. be.title .. ']] || ')
        end
    end

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

return p