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

Renders an icon as wikitext, with optional trailing text and an optional link on that text. It is the rendering core of the icon system: Template:Icon invokes it directly with a filename, and dataset wrapper templates such as Template:Ammo and Template:Currency invoke it with a dataset name and key.

The module exposes a single public entry point: Icon.main, the {{#invoke:}} entry point used by all templates. It accepts either a direct icon filename or a dataset name and key. When a filename is supplied, the module looks it up in Module:Icon/index to resolve CSS classes; when a dataset name and key are supplied, it resolves the entry directly from the named dataset. It produces a TemplateStyles tag followed by the icon image, and a styled label span containing the text when text is supplied.

Editors placing an icon on a page should use Template:Icon rather than invoking this module directly.

Arguments

The module accepts two mutually exclusive input paths.

Direct path, used by Template:Icon:

  • icon (required): file name of the icon.

Dataset path, used by wrapper templates:

  • dataset (required): name of the dataset at Module:Icon/data/<dataset>.
  • key (required): lookup key within the dataset; lowercased before matching.

The following optional arguments apply to both paths:

  • text (optional): label rendered after the icon.
  • link (optional): link target for the label. Treated as an internal page name unless it begins with a URL scheme or //, in which case it is rendered as an external link.
  • size (optional): pixel size of the icon image; defaults to 22.

Errors

Raises an error when no icon can be determined, when dataset or key is supplied without the other, when the named dataset does not exist, or when the supplied key is not found in the dataset. All errors are caught by main, rendered as an inline <span class="error">, and tracked via Category:Pages with icon errors.

See also


--- Renders an icon image with optional trailing text and link.
--- Accepts either a direct icon file or a dataset key for lookup.

local Icon = {}

local DEFAULT_SIZE = 22
local STYLESHEET = 'Template:Icon/styles.css'
local ERROR_CATEGORY = 'Pages with icon errors'

--- Trim whitespace from a value and return nil if the result is blank.
local function nilIfBlank(value)
    local trimmed = value and mw.text.trim(value)
    return trimmed ~= '' and trimmed or nil
end

--- Render an inline error message and add the tracking category.
local function renderError(message)
    local span = tostring(mw.html.create('span'):addClass('error'):wikitext(message)
    )
    return span .. '[[Category:' .. ERROR_CATEGORY .. ']]'
end

--- Load a dataset and return the entry for the given key.
--- The dataset name is lowercased when resolving the page path.
--- Raises an error if the dataset does not exist or the key is not found.
local function loadEntry(dataset, key)
    local page = 'Module:Icon/data/' .. mw.ustring.lower(dataset)
    local success, data = pcall(mw.loadData, page)
    if not success then
        error(string.format('Module:Icon: dataset "%s" not found at %s', dataset, page), 0)
    end
    local entry = data[mw.ustring.lower(key)]
    if not entry then
        error(string.format('Module:Icon: no entry "%s" in dataset "%s"', key, dataset), 0)
    end
    return entry
end

--- Resolve a dataset entry from raw args.
--- Checks for dataset and key first (wrapper template path), then looks up the
--- icon filename in Module:Icon/index (direct path). Returns nil if no entry
--- is found, falling back to direct rendering without dataset resolution.
local function resolveEntry(rawArgs)
    local dataset = nilIfBlank(rawArgs.dataset)
    local key     = nilIfBlank(rawArgs.key)

    -- Wrapper template path: dataset and key supplied directly.
    if dataset and key then
        return loadEntry(dataset, key)
    elseif dataset then
        error(string.format('Module:Icon: missing key for dataset "%s"', dataset), 0)
    elseif key then
        error('Module:Icon: missing dataset', 0)
    end

    -- Direct path: look up the icon filename in the index.
    local icon = nilIfBlank(rawArgs.icon)
    if icon then
        local ok, index = pcall(mw.loadData, 'Module:Icon/index')
        local ref = ok and index[(mw.ustring.lower(icon):gsub(' ', '_'))]
        if ref then
            return loadEntry(ref.dataset, ref.key)
        end
    end
end

--- Normalize raw args into a clean table.
--- Delegates dataset resolution to resolveEntry and falls back to direct
--- rendering if no entry is found. Raises an error if no icon can be determined.
local function normalizeArgs(rawArgs)
    rawArgs = rawArgs or {}

    local entry = resolveEntry(rawArgs) or {}
    local icon  = entry.icon or nilIfBlank(rawArgs.icon)

    if not icon then
        error('Module:Icon: missing icon', 0)
    end

    local rawSize    = rawArgs.size
    local parsedSize = tonumber(rawSize)
        or tonumber(rawSize and string.match(rawSize, '%d+'))
        or DEFAULT_SIZE

    return {
        icon    = icon,
        text    = nilIfBlank(rawArgs.text),
        link    = nilIfBlank(rawArgs.link),
        size    = parsedSize,
        classes = entry.classes,
    }
end

--- Wrap text in an internal or external wiki link.
--- Assumes link is non-nil; callers must guard against nil.
local function wrapLink(link, text)
    if link:match('^%w*:?//') then
        return string.format('[%s %s]', link, text)
    end
    return string.format('[[%s|%s]]', link, text)
end

--- Build the trailing label span for an icon, wrapping the linked or plain
--- text in a styled span. Returns empty string if there is no text.
local function buildLabel(link, text)
    if not text then return '' end
    local content = link and wrapLink(link, text) or text
    return tostring(
        mw.html.create('span'):addClass('icon-text'):wikitext(content)
    )
end

--- Wrap the icon in a span carrying the icon class and any modifier
--- classes supplied by the dataset entry.
local function buildIconSpan(image, classes)
    local span = mw.html.create('span'):addClass('icon')
    for _, class in ipairs(classes or {}) do
        span:addClass(class)
    end
    return tostring(span:wikitext(image))
end

--- Load the TemplateStyles tag for the icon stylesheet.
local function loadStyles()
    return mw.getCurrentFrame():extensionTag{
        name = 'templatestyles',
        args = {src = STYLESHEET}
    }
end

--- Build the icon wikitext from raw args.
local function buildIcon(rawArgs)
    local args  = normalizeArgs(rawArgs)
    local image = string.format('[[File:%s|%dpx|link=]]', args.icon, args.size)
    return loadStyles() .. buildIconSpan(image, args.classes) .. buildLabel(args.link, args.text)
end

--- Entry point for: {{#invoke:Icon|main|...}}
--- Catches errors raised during rendering and displays them inline
--- with a tracking category for maintenance.
function Icon.main(frame)
    local success, result = pcall(buildIcon, frame.args)
    return success and result or renderError(result)
end

--- Return the raw dataset entry for a given key.
--- Callers receive the full entry table, including icon filename and classes.
function Icon.getEntry(dataset, key)
    return loadEntry(dataset, key)
end

return Icon