Jump to content

Module:PadUtils: Difference between revisions

From PAD Wiki
No edit summary
No edit summary
Line 73: Line 73:
--  ol    : "1"/"true" to use <ol> for dungeons; floors are always <ul>
--  ol    : "1"/"true" to use <ol> for dungeons; floors are always <ul>
--  order  : "name" or "id" (defaults to name)
--  order  : "name" or "id" (defaults to name)
-- Build a nested list of all dungeons and their floors from Cargo.
-- Args (all optional):
--  type      : filter by Type (e.g., "Daily")
--  ol        : "1"/"true" -> numbered dungeons; floors stay bulleted
--  order    : "name" (default) or "id"  -- top-level and floor order
--  showcount : "1"/"true" -> append (N) after each dungeon name
--  limit    : max rows to fetch (default 5000)
function p.dungeonIndex(frame)
function p.dungeonIndex(frame)
     local args   = frame.args
     local args     = frame.args
     local useOL = (args.ol == "1" or args.ol == "true")
     local useOL   = (args.ol == "1" or args.ol == "true")
     local typ   = args.type and mw.text.trim(args.type) or nil
     local typ     = args.type and mw.text.trim(args.type) or nil
     local order  = (args.order == "id") and "Dungeon, Name, DungeonFloorID" or "Dungeon, Name"
     local byID    = (args.order == "id")
    local showCnt  = (args.showcount == "1" or args.showcount == "true")
    local limit    = tonumber(args.limit) or 5000


     -- build where clause
     local fields = 'Dungeon, Name'
     local where = nil
    local orderBy = byID and 'Dungeon, DungeonFloorID, Name' or 'Dungeon, Name'
 
     local where
     if typ and typ ~= "" then
     if typ and typ ~= "" then
         where = string.format("Type = '%s'", typ:gsub("'", "''"))
         where = string.format("Type = '%s'", typ:gsub("'", "''"))
     end
     end


    -- query all floors, ordered so we can group by Dungeon
     local rows = mw.ext.cargo.query(
     local rows = mw.ext.cargo.query(
         'dungeon_floors',
         'dungeon_floors',
         'Dungeon, Name',
         fields,
         {
         { where = where, orderBy = orderBy, limit = limit }
            where = where,
            groupBy = nil,
            orderBy = order,
            limit = 5000  -- adjust as needed
        }
     )
     )


Line 101: Line 106:
     end
     end


     -- Build wikitext with one pass, grouping by Dungeon
     -- group
    local grouped, order = {}, {}
    for _, r in ipairs(rows) do
        local d = r.Dungeon
        grouped[d] = grouped[d] or {}
        table.insert(grouped[d], r.Name)
    end
    for d,_ in pairs(grouped) do table.insert(order, d) end
    table.sort(order) -- top-level alphabetical (unless you prefer DB order)
 
    -- build wikitext bullets then parse
     local out = {}
     local out = {}
     local listOpen = useOL and "# " or "* "
     for _, dungeon in ipairs(order) do
    local currentDungeon = nil
        local floors = grouped[dungeon]
    local floorLines = {}
         if not byID then table.sort(floors) end  -- ensure alphabetical floors by default
 
    local function flushDungeon()
         if not currentDungeon then return end
        -- Top-level bullet: the dungeon itself
        table.insert(out, (useOL and "# " or "* ") .. string.format('[[%s|%s]]', currentDungeon, currentDungeon))
        -- Nested bullets for floors
        if #floorLines > 0 then
            for _, line in ipairs(floorLines) do
                table.insert(out, (useOL and "## " or "** ") .. line)
            end
        end
        floorLines = {}
    end


    for _, r in ipairs(rows) do
         local dungeonLabel = dungeon
         local dungeon = r.Dungeon
        if showCnt then dungeonLabel = string.format('%s (%d)', dungeonLabel, #floors) end
         local name    = r.Name
         table.insert(out, (useOL and "# " or "* ") .. string.format('[[%s|%s]]', dungeon, dungeonLabel))


         if dungeon ~= currentDungeon then
         for _, name in ipairs(floors) do
             -- close previous group
             local target = string.format('%s/%s', dungeon, name)
             flushDungeon()
             table.insert(out, (useOL and "## " or "** ") .. string.format('[[%s|%s]]', target, name))
            currentDungeon = dungeon
         end
         end
        -- floor link always dungeon/floor
        local target = string.format("%s/%s", dungeon, name)
        local link  = string.format('[[%s|%s]]', target, name)
        table.insert(floorLines, link)
     end
     end
    -- flush last dungeon
    flushDungeon()


    -- Parse as wikitext so bullets/links render
     return frame:preprocess(table.concat(out, "\n"))
     return frame:expandTemplate{ title = "Template:CargoDisplay", args = { table.concat(out, "\n") } }
end
end


return p
return p

Revision as of 05:13, 22 August 2025

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

-- Module:PadUtils
local p = {}

-- split "A;B;C" safely (ignores empty pieces)
local function split(text, delim)
    local out = {}
    if not text or text == "" then return out end
    for part in mw.text.gsplit(text, delim, true) do
        part = mw.text.trim(part)
        if part ~= "" then table.insert(out, part) end
    end
    return out
end

-- Accept any of:
--   "Floor Name"
--   "Floor_Target|Floor Label"
--   "[[Dungeon/Floor_Target|Floor Label]]"
--   "[[Floor_Target|Floor Label]]"
local function parseItem(item)
    local inner = item:match("^%[%[(.*)%]%]$")
    if inner then item = inner end
    local t, l = item:match("^(.-)|(.*)$")
    local target = mw.text.trim(t or item)
    local label  = mw.text.trim(l or item)
    return target, label
end

-- Always normalize to "base/floor" for the link target.
-- If target already starts with "base/", strip that prefix first.
local function normalizeTarget(base, target)
    target = mw.text.trim(target)
    local withSlash = base .. "/"
    if target:sub(1, #withSlash) == withSlash then
        target = target:sub(#withSlash + 1)
    end
    return base .. "/" .. target
end

function p.dungeonFloors(frame)
    local args    = frame.args
    local base    = args.base and mw.text.trim(args.base) or mw.title.getCurrentTitle().fullText
    local floors  = split(args.floors or "", ";")
    local ordered = (args.ol == "1" or args.ol == "true")
    local before  = args.before or ""
    local after   = args.after or ""

    if #floors == 0 then return "" end

    local lines = {}
    for _, raw in ipairs(floors) do
        local target, label = parseItem(raw)
        local titleText = normalizeTarget(base, target)

        local titleObj   = mw.title.new(titleText)
        local linkTarget = titleObj and titleObj.prefixedText or titleText  -- <-- fixed

        local bullet = ordered and "#" or "*"
        table.insert(lines, string.format("%s [[%s|%s%s%s]]", bullet, linkTarget, before, label, after))
    end

    return frame:preprocess(table.concat(lines, "\n"))
end

-- Module:PadUtils (append this function)
local p = {}

-- ... (keep your other helpers / functions above)

-- Build a nested list of all dungeons and their floors from Cargo.
-- Optional args:
--   type   : filter by Type (e.g., "Daily")
--   ol     : "1"/"true" to use <ol> for dungeons; floors are always <ul>
--   order  : "name" or "id" (defaults to name)
-- Build a nested list of all dungeons and their floors from Cargo.
-- Args (all optional):
--   type      : filter by Type (e.g., "Daily")
--   ol        : "1"/"true" -> numbered dungeons; floors stay bulleted
--   order     : "name" (default) or "id"   -- top-level and floor order
--   showcount : "1"/"true" -> append (N) after each dungeon name
--   limit     : max rows to fetch (default 5000)
function p.dungeonIndex(frame)
    local args     = frame.args
    local useOL    = (args.ol == "1" or args.ol == "true")
    local typ      = args.type and mw.text.trim(args.type) or nil
    local byID     = (args.order == "id")
    local showCnt  = (args.showcount == "1" or args.showcount == "true")
    local limit    = tonumber(args.limit) or 5000

    local fields = 'Dungeon, Name'
    local orderBy = byID and 'Dungeon, DungeonFloorID, Name' or 'Dungeon, Name'

    local where
    if typ and typ ~= "" then
        where = string.format("Type = '%s'", typ:gsub("'", "''"))
    end

    local rows = mw.ext.cargo.query(
        'dungeon_floors',
        fields,
        { where = where, orderBy = orderBy, limit = limit }
    )

    if not rows or #rows == 0 then
        return "''No results''"
    end

    -- group
    local grouped, order = {}, {}
    for _, r in ipairs(rows) do
        local d = r.Dungeon
        grouped[d] = grouped[d] or {}
        table.insert(grouped[d], r.Name)
    end
    for d,_ in pairs(grouped) do table.insert(order, d) end
    table.sort(order) -- top-level alphabetical (unless you prefer DB order)

    -- build wikitext bullets then parse
    local out = {}
    for _, dungeon in ipairs(order) do
        local floors = grouped[dungeon]
        if not byID then table.sort(floors) end  -- ensure alphabetical floors by default

        local dungeonLabel = dungeon
        if showCnt then dungeonLabel = string.format('%s (%d)', dungeonLabel, #floors) end
        table.insert(out, (useOL and "# " or "* ") .. string.format('[[%s|%s]]', dungeon, dungeonLabel))

        for _, name in ipairs(floors) do
            local target = string.format('%s/%s', dungeon, name)
            table.insert(out, (useOL and "## " or "** ") .. string.format('[[%s|%s]]', target, name))
        end
    end

    return frame:preprocess(table.concat(out, "\n"))
end


return p