Module:AbilitySection

Revision as of 09:44, 1 May 2026 by Vergir (talk | contribs) (Add AbilitySection module)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Overview

Lua backend for Template:AbilitySection. Renders a two-column layout with the ability card on the left and an optional tabbed details panel on the right.

Between the card and the details panel, an interaction-hint rail of small item icons is rendered via Module:AbilityHints (showing how the ability interacts with items — dispellable, reduced, blocked, etc.). When a rail is present, the card and rail are grouped in a .ability-section-main wrapper so the rail always wraps together with the card rather than onto the details' line; abilities with no interactions keep the flat single-card structure.

Only tabs with non-empty content are shown. If two or more tabs have content, a Show All tab is automatically appended that stacks all content in sequence with section headers between them.

The Notes tab is height-constrained with a scrollbar when content overflows (see Template:AbilitySection/styles.css). Other tabs are unconstrained.

If no content params are provided, no details panel is rendered at all — only the ability card (and its hint rail, if any).

Entry point

p.render(frame)

Called via {{#invoke:AbilitySection|render}}.

Argument Required Description
hero_name Yes Passed through to Template:Ability card v2.
ability_num Yes Passed through to Template:Ability card v2.
notes No Wikitext for the Notes tab.
tips No Wikitext for the Tips tab.

Constants

TABS

Defines list of possible tabs. Order here determines display order in the tabber.

local TABS = {
    { key = 'notes',        label = 'Notes'        },
    { key = 'tips',         label = 'Tips'         },
}

Example

{{AbilitySection
| hero_name   = Abrams
| ability_num = 1
| notes =
* This is an example of a note.
| tips =
* This is an example of a tip.
}}

Siphon Life



Radius 8m




Duration 4s



Number of Charges 0


Cooldown 42s



Drain health from nearby enemies, dealing spirit damage over time and healing for a portion of the damage dealt.

x0.6


22

Damage Per Second



4s

Duration
On Hit:



70%

Lifesteal

35%  Lifesteal vs Non-Heroes 

Ability Point1
-20s Cooldown
Ability Point2
2s Duration
Ability Point5
+2m Radius and +18 DPS with improved Spirit scaling
  • This is an example of a note.

  • This is an example of a tip.

Notes
  • This is an example of a note.
Tips
  • This is an example of a tip.

-- see /doc for docs

local p = {}

-- Tab definitions — order here determines display order.
local TABS = {
	{ key = 'notes',        label = 'Notes'        },
	{ key = 'interactions', label = 'Interactions' },
	{ key = 'tips',         label = 'Tips'         },
}

local function trim(s)
	return s:match('^%s*(.-)%s*$')
end

local function build_tabber(wikitext_map)
	local filled = {}
	for _, tab in ipairs(TABS) do
		if wikitext_map[tab.key] ~= '' then
			table.insert(filled, { key = tab.key, label = tab.label, wikitext = wikitext_map[tab.key] })
		end
	end

	if #filled == 0 then
		return ''
	end

	local tabs = {}
	for _, section in ipairs(filled) do
		table.insert(tabs, {
			label   = section.label,
			content = '<div class="ability-details-panel">\n' .. section.wikitext .. '\n</div>',
		})
	end

	-- "Show All" tab wraps each section's wikitext in a <div> to give the parser
	-- a fresh block context per section, preventing html mangling.
	if #filled >= 2 then
		local all_parts = {}
		for _, section in ipairs(filled) do
			table.insert(all_parts,
				'<div class="ability-details-section-header">' .. section.label .. '</div>'
				.. '<div class="ability-details-section-content">\n' .. section.wikitext .. '\n</div>'
			)
		end
		table.insert(tabs, {
			label   = 'Show All',
			content = '<div class="ability-details-panel">' .. table.concat(all_parts) .. '</div>',
		})
	end

	return mw.ext.tabber.render(tabs)
end

-- Entry point. Called via {{#invoke:AbilitySection|render}}.
function p.render(frame)
	local args         = frame.args
	local hero_name    = trim(args.hero_name or '')
	local ability_num  = trim(args.ability_num or '')
	local notes        = trim(args.notes or '')
	local interactions = trim(args.interactions or '')
	local tips         = trim(args.tips or '')

	local card = frame:expandTemplate{
		title = 'Ability card v2',
		args  = { hero_name = hero_name, ability_num = ability_num, link_name = 'false' }
	}

	local wikitext_map = {
		notes        = notes,
		interactions = interactions,
		tips         = tips,
	}

	local tabber = build_tabber(wikitext_map)
	local notes_col = ''
	if tabber ~= '' then
		notes_col = '<div class="ability-section-notes">' .. tabber .. '</div>'
	end

	return '<div class="ability-section">'
		.. '<div class="ability-section-card">' .. card .. '</div>'
		.. notes_col
		.. '</div>'
end

return p