Module:Tooltip

This module depends on the following other modules:
Module:Arguments
Module:Color
Module:Iconify
Edit documentation

This module is similar to {{Tooltip}} but for modules. It contains a number of related utility functions.

tooltip

This function generates a tooltip with the display text shown on the wiki page and the header and body shown when hovering over the display text.

Parameter Description Required Default
1 Text/content shown on page (displayText) required none
2 Initial text/content of tooltip (header) optional none
3 Final text/content of tooltip (body) optional none
tagType HTML tag used to wrap tooltip
  • span: allows default inline use in paragraphs
  • div: requires wrapping paragraphs in span or div
optional div
index tooltip level, for tooltip-in-a-tooltip
  • 1, 2, or 3
optional none
style CSS style effects for tooltip optional none

Numbered parameters must be passed in order, named parameters must be passed as a table following; i.e. tooltip( 1, 2, 3, { tagType = val, index = val, style = val } ) Empty strings must be used for empty header or body if using named parameters.

headerStyle

This function makes it easier to style the header for tooltips by providing a standard frame

Parameter Description Required Default
1 Name of header style (headerType) required none
mainText Main text/title optional none
subText Subtitle optional none
leftText Text/content to left of mainText optional none
rightText Text/content to right of mainText optional none
extra Additional CSS style effects for tooltip optional none

Numbered parameters must be passed in order, named parameters must be passed as a table following; i.e. headerStyle( 1, { mainText = val, subText = val, leftText = val, rightText = val, extra = val } )

ttList

This function creates a list of tooltippable items

Parameter Description Required Default
1 Table of arrays (listTable)
  • If the array key matches a function, array elements are passed one by one to that function as the first table argument.
  • Otherwise, array elements are returned
required none
multiKey Text header for arrays with multiple items optional Any of:
index Tooltip level, disables tooltipping by default optional 4
listStyle Sets styling of list
  • inline: uses <br> tags between each line, for use in tooltips
  • newline: uses indent and newlines for a proper list, for use in tables
optional inline
indent Sets list level and type for newline optional *

Numbered parameters must be passed in order, named parameters must be passed as a table following; i.e. ttList( 1, { multiKey = val, index = val, listStyle = val, indent = val } )

effectList

This function creates a list of modifier effects

Parameter Description Required Default
1 Table of arrays or 'pseudo'-arrays (list) required none
color Passes table of named arguments for Module:Color optional none
listStyle Sets styling of list
  • inline: uses <br> tags between each line, for use in tooltips
  • newline: uses indent and newlines for a proper list, for use in tables
optional inline
indent Sets list level and type for newline optional *
icon Sets an {{Iconify}} icon "group" for each effect
  • Only usable if all effects have the same icon group
optional none
page Sets a page link for alternate linking with icon optional icon

The array elements must be formatted as in the table below. Color values can be any that are valid for Module:Color. If using an array, the third argument can be a table of parameters for Module:Iconify as well, which then uses the color and value as a mod parameter.

Numbered parameters must be passed in order, named parameters must be passed as a table following; i.e. effectList( 1, { color = val, listStyle = val, indent = val, icon = val, page = val } )

Valid effect formats:
No icon/prefix With icon/prefix
"<color>_<value>_<text>" "<color>_<value>_<text>_<prefix>"
{ "<color>", "<value>", "<text>" } { "<color>", "<value>", "<text>", "<prefix>"/icon = "<prefix>" }
{ "<color>", "<value>", { icon="<text>", <other iconify parameters as needed> } }
"<text>"
{ "<text>" }

local uFormat = mw.ustring.format
local htmlCreate = mw.html.create
local getArgs = require('Module:Arguments').getArgs
local p = {};

function p.main(frame)
    local args = getArgs(frame)
    --[[
    local funct = {}
        funct.tooltip = p.tooltip(args[1], args.header, args.body, args)
        funct.headerStyle = p.headerStyle(args[1], args)
        funct.ttList = p.ttList(args[1], args)
        funct.effectList = p.effectList(args[1], args)
    --]]
    return p.tooltip(args[1], args.header, args.body, args) --funct[args.funct]
end

function p.tooltip(displayText, header, body, options)
    options = options or {} -- allow null options
    local tagType = options.tagType or 'div' -- expects span or similar html tag

    local index = tonumber(options.index) -- force number
    if type(index) ~= 'number' or index > 3 then -- any non number or index over 3 returns basic display
        return tostring(htmlCreate(tagType):css('display','inline'):wikitext(displayText))
    elseif index < 2 then
        index = '' -- 1st index is unnumbered in CSS
    end
    -- empty string if nil header or body
    header = header or ''
    body = body or ''
    local tt = htmlCreate(tagType)
        :addClass('tooltip'..index)
        :wikitext(displayText)

    tt:tag(tagType)
        :addClass('tooltiptext'..index)
        :cssText(options.style)
        :wikitext(header,body)

    return tostring(tt)
end

-- sets header style within tooltip, only one style currently
function p.headerStyle(headerType, args)
    args = args or {} -- allow null options

    -- start list of header types
    local headerTypes = {}

 -- header with left float (icon), right float (group/category), and two lines of text, with gradient backing matching in-game style
    headerTypes.twoLineLr = tostring(
        htmlCreate('div'):cssText("display: flex; background: linear-gradient(to right, #5c42565a, #47373a3a);"):cssText(args.extra)
        :tag('div'):css('margin-right','5px'):wikitext(args.leftText):done()
        :tag('div'):css('width','100%')
        :tag('span'):cssText('float: right; text-align: right; margin-left: 5px;'):wikitext(args.rightText):done()
        :tag('span'):cssText("color: white; font-weight:bold;"):wikitext(args.mainText):done()
        :wikitext('<br>',args.subText):done()
    )
    headerTypes['2LR'] = headerTypes.twoLineLr -- shorthand

    return headerTypes[headerType]
end

-- assumes listTable is table containing arrays, t1 = { t2 = { 1, 2, ... }, ... }
function p.ttList(listTable, args)
    args = args or {} -- allow null options

    local t = args.functs or {}
    t.pm = t.pm or require('Module:Production method').productionMethod
    t.building = t.building or require('Module:Building').building
    t.tech = t.tech or require('Module:Technology').tech
    t.law = t.law or require('Module:Law').law
    t.decree = t.decree or require('Module:Decree').decree
    t.ideology = t.ideology or require('Module:Ideology').ideology
    t.unit = t.unit or require('Module:Unit').unit

    local uSub = mw.ustring.sub
    local list = "" -- return string
    local multiKey = args.multiKey or "Any of:"
    local index = tonumber(args.index) or 4
    local newline = args.listStyle == "newline" -- inline, newline
    local indent = args.indent or "*"
    -- set newline style
    local lineIndent = newline and '\n'..indent or ''

    -- main loop; look at table and return arrays
    for functName, arr in pairs(listTable) do
        local lt = {} -- table of processed values
        local i = 1 -- iterator, reused for substring
        -- loop through array
        for _, v in ipairs(arr) do
            if type(t[functName]) == 'function' then
                v = t[functName]{v, index=index, from=args.from, fromfrom=args.fromfrom}
            elseif (not newline) then
                v = tostring(htmlCreate('div'):wikitext(v))--uFormat("<div>%s</div>", v)
            end
            -- table
            lt[i] = v
            i = i + 1
        end
        -- prepend multiKey for arrays with 2 or more elements
        if arr[2] and (not newline) and (multiKey ~= "") then
            i = tostring(htmlCreate('div'):wikitext(multiKey)
                :tag('div'):cssText('display:grid; justify-items: start; margin-left:1em;'):wikitext(table.concat(lt)):done())
        elseif arr[2] and newline and (multiKey ~= "") then
            -- increase indent level by one, and prepend multiKey
            table.insert(lt, 1, multiKey) -- with multiKey as first element, should use default indent
            i = uFormat("%s %s", lineIndent, table.concat(lt, lineIndent .. uSub(indent, -1)))
        else
            i = lineIndent..table.concat(lt, lineIndent)
        end
        if #lt > 5 and (multiKey == "") then
            i = '<div style="display:grid; justify-items: start; grid-template-columns: auto auto; gap:0px 10px;">'..i..'</div>'
        end
        list = list .. i
    end
    if not newline then
        list = '<div style="display:grid; justify-items: start; margin-left:1em;">'..list..'</div>'
    end
    return list
end

-- assumes list is array containing 'pseudo'-arrays, t1 = { 'e1_e2_e3', ... }, or actual arrays, t1 = { 1 = { e1, e2, e3 }, ... }
-- single value effects can be passed for a 'plain'text output
function p.effectList(list, args)
    args = args or {} -- allow null options
    local colorMod = require('Module:Color').color
    local iconify = require('Module:Iconify').iconify
    local l = "" -- return string
    args.color = args.color or {}
    local newline = args.listStyle == "newline" -- inline, newline
    local indent = args.indent or "*"
    local textSplit = mw.text.split

--enough for now
    local function deepCopyTable(original)
        local copy = {}
        for k, v in pairs(original) do
            if type(v) == "table" then
                -- Recursively copy tables
                copy[k] = deepCopyTable(v)
            else
                -- Directly copy non-table values
                copy[k] = v
            end
        end
        return copy
    end
    -- main loop
    for _, effect in ipairs(list) do
        local effects
        local s = '' -- substring
        if type(effect) == 'string' then
            effects = textSplit(effect,"_") -- split effect pseudo-sub-array into actual array
        elseif type(effect) == 'table' then
            effects = deepCopyTable(effect)
        else
            return '<span style="color:red; font-size:11px;">Invalid effect list given</span>'
        end
        args.page = args.page or args.icon
        local color = colorMod(effects[1], effects[2], args.color) -- color, value, text
        if #effects == 1 then
            s = effects[1] -- single value effect (no effect size)
        elseif args.page and args.icon then
            s = iconify{icon=effects[3], group=args.icon, width="20px", mod=color, link=args.page.."#"..effects[3], extra=effects[3]}
        elseif type(effects[3]) == 'table' then
            local efIc = {}
            for k, v in pairs(effects[3]) do efIc[k] = v end
            efIc.mod = color -- add mod arg
            s = iconify(efIc) -- pass-through table of iconify args
        elseif effects[4] or effects.icon then
            local icon = effects[4] or effects.icon
            s = uFormat("%s %s %s", icon, color, effects[3])
        else
            s = uFormat("%s %s", color, effects[3])
        end
        if not newline then l = l .. s .. "<br>"
        elseif newline then l = uFormat("%s\n%s %s",l, indent, s)
        end
    end
    if not newline then l = l:sub(1, -5) end -- trim last <br>
    return l
end

return p