Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:Infobox: Difference between revisions

From Piñata Journal
No edit summary
No edit summary
 
(5 intermediate revisions by the same user not shown)
Line 11: Line 11:


local p = {}
local p = {}
local journalLabels = {
journal_tip = "Trouble in Paradise",
journal_pp  = "Pocket Paradise",
journal_vp1 = "Viva Piñata"
}


-- Utility: trim whitespace
-- Utility: trim whitespace
Line 26: Line 33:


-- Render journal section
-- Render journal section
local function renderJournal(args)
local function renderJournal(args, frame)
-- collect journal_* params
    local journals = {}
local journals = {}


for k, v in pairs(args) do
    for k, v in pairs(args) do
if type(k) == "string" and k:match("^journal_") then
        if type(k) == "string" and k:match("^journal_") then
local val = trim(v)
            local val = trim(v)
if val then
            if val then
table.insert(journals, {
                table.insert(journals, {
key = k,
                    label = journalLabels[k] or titleCase(
label = k:gsub("^journal_", ""):gsub("_", " "),
                        k:gsub("^journal_", ""):gsub("_", " ")
text = val
                    ),
})
                    text = val
end
                })
end
            end
end
        end
    end


-- legacy single journal
    if #journals == 0 then
if #journals == 0 and trim(args.journal) then
        return nil
return args.journal
    end
end


if #journals == 0 then
    -- SINGLE
return nil
    if #journals == 1 then
end
        return frame:preprocess(journals[1].text)
    end


-- single journal: no <details>
    -- MULTI (emit wikitext!)
if #journals == 1 then
    local out = {}
return journals[1].text
end


-- multiple journals: details blocks
    for i, j in ipairs(journals) do
local out = {}
        table.insert(out, string.format([[
table.insert(out, '<div class="vp-journal-multi">')
<details class="vp-journal-block"%s>
<summary>%s</summary>
<div class="vp-journal-text">
%s
</div>
</details>
]], i == 1 and " open" or "", j.label, j.text))
    end


for i, j in ipairs(journals) do
    return frame:preprocess(table.concat(out, "\n"))
local open = (i == 1) and " open" or ""
end
table.insert(out,
string.format(
'<details class="vp-journal-block"%s><summary>%s</summary><div class="vp-journal-text">%s</div></details>',
open,
titleCase(j.label),
j.text
)
)
end


table.insert(out, '</div>')
return table.concat(out)
end


-- Main renderer
-- Main renderer
function p.render(frame)
function p.render(frame)
local args = frame:getParent().args
    local args = frame:getParent().args
 
    local name = trim(args.name) or mw.title.getCurrentTitle().text
    local image = trim(args.image)
 
    -- reserved params
    local reserved = {
        name = true,
        image = true,
        journal = true
    }
    for k, _ in pairs(args) do
        if type(k) == "string" and k:match("^journal_") then
            reserved[k] = true
        end
    end


local name = trim(args.name) or mw.title.getCurrentTitle().text
    -- build table
local image = trim(args.image)
    local tableNode = mw.html.create('table')
    tableNode:addClass('infobox')
    tableNode:addClass('infobox-generic')


-- rows: everything except reserved params
    -- header
local reserved = {
    tableNode:tag('tr')
name = true,
        :tag('th')
image = true,
            :attr('colspan', 2)
journal = true
            :addClass('infobox-header')
}
            :wikitext(name)
for k, _ in pairs(args) do
if k:match("^journal_") then
reserved[k] = true
end
end


local rows = {}
    -- image
    if image then
        tableNode:tag('tr')
            :tag('td')
                :attr('colspan', 2)
                :addClass('infobox-image')
                :wikitext(string.format('[[File:%s|250px|center|%s]]', image, name))
    end


for k, v in pairs(args) do
    -- journal
if not reserved[k] then
    local journalHTML = renderJournal(args, frame)
local val = trim(v)
    if journalHTML then
if val then
        tableNode:tag('tr')
table.insert(rows, {
            :tag('td')
label = titleCase(k:gsub("_", " ")),
                :attr('colspan', 2)
value = val
                :addClass('infobox-section')
})
                :addClass('infobox-journal-cell')
end
                :node(journalHTML)
end
    end
end


-- Begin table
    -- FIXED ORDER KEYS
local html = {}
    local fixedOrder = {
table.insert(html, '<table class="infobox infobox-generic">')
        "level",
        "base_value",
        "animal",
        "candy",
        "attack_object",
        "role",
        "relationships",
        "voiced_by"
    }


-- Header
    for _, k in ipairs(fixedOrder) do
table.insert(html,
        local v = args[k]
string.format(
        if v then
'<tr><th colspan="2" class="infobox-header">%s</th></tr>',
            local val = trim(v)
esc(name)
            if val then
)
                local row = tableNode:tag('tr')
)


-- Image
                row:tag('td')
if image then
                    :addClass('infobox-section')
table.insert(html,
                    :addClass('infobox-label-cell')
string.format(
                    :tag('span')
'<tr><td colspan="2" class="infobox-image">[[File:%s|250px|center|%s]]</td></tr>',
                        :addClass('infobox-label')
image,
                        :wikitext(titleCase(k:gsub("_", " ")))
esc(name)
)
)
end


-- Journal
                row:tag('td')
local journalHTML = renderJournal(args)
                    :addClass('infobox-section')
if journalHTML then
                    :addClass('infobox-value-cell')
table.insert(html,
                    :wikitext(val)
'<tr><td colspan="2" class="infobox-section infobox-journal-cell">' ..
            end
journalHTML ..
            reserved[k] = true
'</td></tr>'
        end
)
    end
end


-- Rows
    -- ANY REMAINING ARGS (alphabetical)
for _, row in ipairs(rows) do
    local remainingKeys = {}
table.insert(html,
    for k in pairs(args) do
string.format(
        if not reserved[k] then
'<tr>' ..
            table.insert(remainingKeys, k)
'<td class="infobox-section infobox-label-cell"><span class="infobox-label">%s</span></td>' ..
        end
'<td class="infobox-section infobox-value-cell">%s</td>' ..
    end
'</tr>',
    table.sort(remainingKeys)
esc(row.label),
row.value
)
)
end


table.insert(html, '</table>')
    for _, k in ipairs(remainingKeys) do
        local val = trim(args[k])
        if val then
            local row = tableNode:tag('tr')


return table.concat(html, "\n")
            row:tag('td')
                :addClass('infobox-section')
                :addClass('infobox-label-cell')
                :tag('span')
                    :addClass('infobox-label')
                    :wikitext(titleCase(k:gsub("_", " ")))
 
            row:tag('td')
                :addClass('infobox-section')
                :addClass('infobox-value-cell')
                :wikitext(val)
        end
    end
 
    return tostring(tableNode)
end
end


return p
return p

Latest revision as of 12:47, 6 February 2026

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

-- Utility: Title Case (capitalize every word)
local function titleCase(s)
	if not s then return nil end
	local lang = mw.language.getContentLanguage()
	s = s:gsub("(%S+)", function(word)
		return lang:ucfirst(word)
	end)
	return s
end


local p = {}

local journalLabels = {
	journal_tip = "Trouble in Paradise",
	journal_pp  = "Pocket Paradise",
	journal_vp1 = "Viva Piñata"
}


-- Utility: trim whitespace
local function trim(s)
	if not s then return nil end
	s = mw.text.trim(s)
	if s == "" then return nil end
	return s
end

-- Utility: escape HTML
local function esc(s)
	return mw.text.nowiki(s)
end

-- Render journal section
local function renderJournal(args, frame)
    local journals = {}

    for k, v in pairs(args) do
        if type(k) == "string" and k:match("^journal_") then
            local val = trim(v)
            if val then
                table.insert(journals, {
                    label = journalLabels[k] or titleCase(
                        k:gsub("^journal_", ""):gsub("_", " ")
                    ),
                    text = val
                })
            end
        end
    end

    if #journals == 0 then
        return nil
    end

    -- SINGLE
    if #journals == 1 then
        return frame:preprocess(journals[1].text)
    end

    -- MULTI (emit wikitext!)
    local out = {}

    for i, j in ipairs(journals) do
        table.insert(out, string.format([[
<details class="vp-journal-block"%s>
<summary>%s</summary>
<div class="vp-journal-text">
%s
</div>
</details>
]], i == 1 and " open" or "", j.label, j.text))
    end

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


-- Main renderer
function p.render(frame)
    local args = frame:getParent().args

    local name = trim(args.name) or mw.title.getCurrentTitle().text
    local image = trim(args.image)

    -- reserved params
    local reserved = {
        name = true,
        image = true,
        journal = true
    }
    for k, _ in pairs(args) do
        if type(k) == "string" and k:match("^journal_") then
            reserved[k] = true
        end
    end

    -- build table
    local tableNode = mw.html.create('table')
    tableNode:addClass('infobox')
    tableNode:addClass('infobox-generic')

    -- header
    tableNode:tag('tr')
        :tag('th')
            :attr('colspan', 2)
            :addClass('infobox-header')
            :wikitext(name)

    -- image
    if image then
        tableNode:tag('tr')
            :tag('td')
                :attr('colspan', 2)
                :addClass('infobox-image')
                :wikitext(string.format('[[File:%s|250px|center|%s]]', image, name))
    end

    -- journal
    local journalHTML = renderJournal(args, frame)
    if journalHTML then
        tableNode:tag('tr')
            :tag('td')
                :attr('colspan', 2)
                :addClass('infobox-section')
                :addClass('infobox-journal-cell')
                :node(journalHTML)
    end

    -- FIXED ORDER KEYS
    local fixedOrder = {
        "level",
        "base_value",
        "animal",
        "candy",
        "attack_object",
        "role",
        "relationships",
        "voiced_by"
    }

    for _, k in ipairs(fixedOrder) do
        local v = args[k]
        if v then
            local val = trim(v)
            if val then
                local row = tableNode:tag('tr')

                row:tag('td')
                    :addClass('infobox-section')
                    :addClass('infobox-label-cell')
                    :tag('span')
                        :addClass('infobox-label')
                        :wikitext(titleCase(k:gsub("_", " ")))

                row:tag('td')
                    :addClass('infobox-section')
                    :addClass('infobox-value-cell')
                    :wikitext(val)
            end
            reserved[k] = true
        end
    end

    -- ANY REMAINING ARGS (alphabetical)
    local remainingKeys = {}
    for k in pairs(args) do
        if not reserved[k] then
            table.insert(remainingKeys, k)
        end
    end
    table.sort(remainingKeys)

    for _, k in ipairs(remainingKeys) do
        local val = trim(args[k])
        if val then
            local row = tableNode:tag('tr')

            row:tag('td')
                :addClass('infobox-section')
                :addClass('infobox-label-cell')
                :tag('span')
                    :addClass('infobox-label')
                    :wikitext(titleCase(k:gsub("_", " ")))

            row:tag('td')
                :addClass('infobox-section')
                :addClass('infobox-value-cell')
                :wikitext(val)
        end
    end

    return tostring(tableNode)
end



return p