Jump to content

Module:Navlists

From Dook & Flops Wiki


Module:Navlists

This module generates lists of page links from one or more categories, optionally including subcategories (recursively).

Functions

listFromCategory
Returns a dot-separated list of pages from a category.
  • 1 – Category name (without the Category: prefix).
  • separator (optional) – String used to separate items. Default: .

Basic usage

{{#invoke:Navlists|listFromCategory|Characters}}

Returns all pages in Category:Characters and its subcategories.

Custom separator

{{#invoke:Navlists|listFromCategory|Characters|separator=, }}

Notes

  • Redirects are excluded.
  • The function detects and avoids category loops.
  • Subcategories are detected recursively.
  • You can create wrapper templates (e.g., Template:NavlistMainCast) for use in navboxes.

See also


local p = {}

-- Build absolute API URL for this wiki
local function apiEndpoint()
    -- Works on standard setups; adjust if you serve from a subdir
    return (mw.site.server or "") .. (mw.site.scriptPath or "") .. "/api.php"
end

-- GET wrapper with JSON decode
local function apiQuery(params)
    params.format = "json"
    local url = apiEndpoint() .. "?" .. mw.uri.buildQueryString(params)
    local res = mw.http.fetch(url)
    if not res or res.status ~= 200 then
        error("Navlists: API HTTP error " .. tostring(res and res.status))
    end
    return mw.text.jsonDecode(res.body)
end

-- Recursively gather pages from a category and its subcategories
local function gather(catTitle, visited, out)
    visited = visited or {}
    out = out or {}

    if visited[catTitle] then return out end
    visited[catTitle] = true

    local cont = nil
    repeat
        local params = {
            action   = "query",
            list     = "categorymembers",
            cmtitle  = catTitle,                -- e.g. "Category:Characters"
            cmtype   = "page|subcat",
            cmlimit  = "500",
        }
        if cont then params.cmcontinue = cont end

        local data = apiQuery(params)
        local members = (data.query and data.query.categorymembers) or {}

        for _, m in ipairs(members) do
            if m.ns == 14 then
                -- Category (ns 14): recurse into it
                gather(m.title, visited, out)
            else
                -- Regular page
                table.insert(out, string.format("[[%s]]", m.title))
            end
        end

        cont = data.continue and data.continue.cmcontinue
    until not cont

    return out
end

-- Public: {{#invoke:Navlists|listFromCategory|CategoryName|separator= • }}
function p.listFromCategory(frame)
    local cat = frame.args[1] or frame:getParent().args[1]
    if not cat or cat == "" then return "" end

    -- Accept "Characters" or "Category:Characters"
    if not cat:match("^[Cc]ategory:") then
        cat = "Category:" .. cat
    end
    local sep = frame.args.separator or frame:getParent().args.separator or " • "

    local links = gather(cat, {}, {})
    table.sort(links, function(a, b)
        -- sort on display title without brackets
        return mw.ustring.lower(a:gsub("[%[%]]", "")) < mw.ustring.lower(b:gsub("[%[%]]", ""))
    end)

    return table.concat(links, sep)
end

return p