Module:EquipmentGallery

From Dune: Awakening Community Wiki
Jump to navigation Jump to search

Module:EquipmentGallery

Queries DPL3 for Menu Garments images matching a given item name, parses the filenames into captioned entries, and returns sorted filename~caption lines compatible with Template:Gallery.

This module should not be invoked directly. To add a dynamic image gallery to a Garment page, use Template:EquipmentGallery.

This module provides the following function(s):

  • main - queries DPL3 for matching garment images, parses the filenames, generates captions, and returns sorted output lines.

Usage

Render a dynamic Equipment gallery

On an Equipment page, via Template:EquipmentGallery:

{{#invoke:EquipmentGallery|main|{{BASEPAGENAME}}}}

Parameters

main

1
string
The item name used as the parsing anchor within each filename and as the DPL3 query target. Typically passed as {{BASEPAGENAME}} from the template.
The value is decoded via mw.text.decode() to handle HTML entities (e.g. ' for apostrophes in page titles like 'Thopter Pilot Set).

Notes

Filename format

The module expects filenames matching the following structure:

Menu Garments <GENDER> [SWATCH] <ITEM_NAME> [SIDE].jpg
GENDER
Masculine or Feminine. Required.
SWATCH
Zero or more words between GENDER and ITEM_NAME. Optional.
ITEM_NAME
Must match the item name parameter. Required.
SIDE
Front or Back. Optional.

local p = {}

local common = require("Module:Common")

-- ---------- Data ----------

local PREFIX = "Menu Garments "
local GENDERS = { Masculine = 1, Feminine = 2 }
local SIDES = { Front = 1, Back = 2 }

local DPL_QUERY = '{{ #dpl: namespace = File | titlematch = Menu Garments%%%s%% | format = ,%%TITLE%%\\n,, }}'

-- ---------- Processing ----------

function p.parseFilename(filename, itemName)
    -- strip prefix
    if filename:sub(1, #PREFIX) ~= PREFIX then
        return nil
    end
    local base = filename:sub(#PREFIX + 1)

    -- strip file extension
    base = base:match("^(.+)%..+$")

    -- extract gender
    local gender, rest = base:match("^(%S+)%s+(.*)")
    if not gender or not GENDERS[gender] then
        return nil
    end

    -- find item name anchor
    local itemPos = rest:find(itemName, 1, true)
    if not itemPos then
        return nil
    end

    -- extract swatch, if present
    local swatch = nil
    if itemPos > 1 then
        local raw = common.trim(rest:sub(1, itemPos - 1))
        if raw ~= "" then
            swatch = raw
        end
    end

    -- extract front/back, if present
    local afterItem = common.trim(rest:sub(itemPos + #itemName))
    local side = nil
    if SIDES[afterItem] then
        side = afterItem
    end

    return {
        gender = gender,
        swatch = swatch,
        side = side,
    }
end

function p.buildCaption(parsed)
    local caption = parsed.swatch and "'''" .. parsed.swatch .. " Swatch'''" or "'''Default Swatch'''"

    caption = caption .. "<br>" .. parsed.gender

    if parsed.side then
        caption = caption .. " (" .. parsed.side .. ")"
    end

    return caption
end

-- ---------- Interface ----------

function p.main(frame)
    local args = frame.args

    local itemName = mw.text.decode(common.trim(args[1] or ""))
    local input = itemName ~= "" and common.trim(frame:preprocess(string.format(DPL_QUERY, itemName))) or ""

    if input == "" then
        return "Placeholder.jpg~No matching images"
    end

    local entries = {}
    for line in input:gmatch("[^\r\n]+") do
        line = common.trim(line)
        if line ~= "" then
            local parsed = p.parseFilename(line, itemName)
            entries[#entries + 1] = {
                filename = line,
                parsed = parsed,
            }
        end
    end

    -- sort order: swatch (none first) > gender (Masc first) > side (Front first)
    table.sort(entries, function(a, b)
        local ap, bp = a.parsed, b.parsed

        -- unparseable entries go to the end
        if not ap then return false end
        if not bp then return true end

        -- push un-swatched images to the front
        local aHas = ap.swatch and 1 or 0
        local bHas = bp.swatch and 1 or 0
        if aHas ~= bHas then return aHas < bHas end

        -- sort swatches alphabetically
        if ap.swatch and bp.swatch and ap.swatch ~= bp.swatch then
            return ap.swatch < bp.swatch
        end

        -- gender
        local aGender = GENDERS[ap.gender]
        local bGender = GENDERS[bp.gender]
        if aGender ~= bGender then return aGender < bGender end

        -- side (but also account for those that don't have front/back yet)
        local aSide = SIDES[ap.side] or 3
        local bSide = SIDES[bp.side] or 3
        return aSide < bSide
    end)

    -- build output lines
    local lines = {}
    for i = 1, #entries do
        local e = entries[i]
        if e.parsed then
            lines[#lines + 1] = e.filename .. "~" .. p.buildCaption(e.parsed)
        else
            lines[#lines + 1] = e.filename
        end
    end

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

return p