Module:Sandbox/LVL

From The Deadlock Wiki
Revision as of 14:56, 7 July 2025 by LVL (talk | contribs) (Created page with "local Tabs = {} -- Helper functions to replace Module:Logic local function readBool(val) if val == nil then return false end if type(val) == 'boolean' then return val end if type(val) == 'string' then val = val:lower() return val == 'true' or val == 'yes' or val == '1' end return false end local function isEmpty(val) if val == nil then return true end if type(val) == 'string' then return val:gsub('%s','') == '' end if typ...")
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

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

local Tabs = {}

-- Helper functions to replace Module:Logic
local function readBool(val)
    if val == nil then return false end
    if type(val) == 'boolean' then return val end
    if type(val) == 'string' then
        val = val:lower()
        return val == 'true' or val == 'yes' or val == '1'
    end
    return false
end

local function isEmpty(val)
    if val == nil then return true end
    if type(val) == 'string' then return val:gsub('%s','') == '' end
    if type(val) == 'table' then return next(val) == nil end
    return false
end

-- Helper to replace Module:Table.extract
local function extractTable(tab, key)
    local val = tab[key]
    tab[key] = nil
    return val
end

-- Helper to replace Module:Array functions
local function arrayForEach(t, f)
    for i, v in ipairs(t) do f(v, i) end
end

local function arrayAny(t, f)
    for _, v in ipairs(t) do if f(v) then return true end end
    return false
end

local function arrayAll(t, f)
    for _, v in ipairs(t) do if not f(v) then return false end end
    return true
end

-- Helper to replace Module:Operator.property
local function property(key)
    return function(obj) return obj[key] end
end

-- Simplified page link generation (replaces Module:Page)
local function makeInternalLink(_, name, link)
    return mw.ustring.format('[[%s|%s]]', link, name)
end

-- Main argument processor
local function readArguments(args, options)
    local tabArgs = {}
    local tabIndex = 1
    local this = tonumber(args.This)
    local this2 = tonumber(args.This2)

    while args['name' .. tabIndex] or args['link' .. tabIndex] do
        local content = args['content' .. tabIndex]
        if content or not options.removeEmptyTabs then
            table.insert(tabArgs, {
                name = extractTable(args, 'name' .. tabIndex),
                link = extractTable(args, 'link' .. tabIndex),
                content = extractTable(args, 'content' .. tabIndex),
                tabs = extractTable(args, 'tabs' .. tabIndex),
                this = this == tabIndex or (options.allowThis2 and this2 == tabIndex),
            })
        end
        tabIndex = tabIndex + 1
    end

    if readBool(args.returnIfEmpty) then
        return tabArgs
    end

    assert(#tabArgs > 0, 'You are trying to add a "Tabs" template without arguments for names nor links')
    return tabArgs
end

-- Automatic this-tab detection
local function setThis(tabArgs)
    if arrayAny(tabArgs, property('this')) then return end

    local fullPageName = mw.title.getCurrentTitle().prefixedText
    local this
    local maxLinkLength = -1

    arrayForEach(tabArgs, function(tab, tabIndex)
        local link = tab.link
        if not link then return end
        link = link:gsub('_', ' ')
        local linkLength = #link
        local charAfter = fullPageName:sub(linkLength + 1, linkLength + 1)
        local pagePartial = fullPageName:sub(1, linkLength)
        if pagePartial == link and (charAfter == '/' or charAfter == '') and linkLength > maxLinkLength then
            maxLinkLength = linkLength
            this = tabIndex
        end
    end)

    if this then tabArgs[this].this = true end
end

-- Content div builder
local function buildContentDiv(hasContent, hybridTabs, noPadding)
    local contentDiv = mw.html.create('div'):addClass('tabs-content')
    if hybridTabs then
        contentDiv:css('border-style', 'none !important')
                 :css('padding', '0 !important')
    elseif noPadding then
        contentDiv:css('padding', '0 !important')
    end
    return contentDiv
end

-- Display name extractor
local function getDisplayNameFromLink(link)
    local parts = {}
    for part in link:gmatch('[^/]+') do
        table.insert(parts, part)
    end
    return parts[#parts] or link
end

-- Main static tabs function
function Tabs.static(args)
    args = args or {}
    local tabArgs = readArguments(args, { allowThis2 = true })
    if #tabArgs == 0 then return nil end

    setThis(tabArgs)

    local tabs = mw.html.create('ul')
        :addClass('nav nav-tabs navigation-not-searchable tabs tabs' .. #tabArgs)
        :attr('data-nosnippet')

    local subTabs = mw.html.create()

    arrayForEach(tabArgs, function(tab)
        local name = tab.name or getDisplayNameFromLink(tab.link or '')
        local text = tab.link and makeInternalLink(nil, name, tab.link) or tab.name
        tabs:tag('li')
            :addClass(tab.this and 'active' or nil)
            :wikitext(text)
        subTabs:node(tab.this and tab.tabs or nil)
    end)

    return mw.html.create()
        :tag('div')
            :addClass('tabs-static')
            :attr('data-nosnippet', '')
            :node(tabs)
            :done()
        :node(subTabs)
end

-- Main dynamic tabs function
function Tabs.dynamic(args)
    args = args or {}
    local tabArgs = readArguments(args, { removeEmptyTabs = readBool(args.removeEmptyTabs) })
    if #tabArgs == 0 then return nil end

    local hasContent = arrayAll(tabArgs, function(tab) return not isEmpty(tab.content) end)
    local allEmpty = arrayAll(tabArgs, function(tab) return isEmpty(tab.content) end)
    assert(hasContent or allEmpty, 'Some tabs have content while others do not')

    local isSingular = #tabArgs == 1 and hasContent
    if isSingular and not readBool(args.showSingularAsTab) then
        local header = nil
        if not readBool(args.suppressHeader) then
            header = mw.html.create('h6'):wikitext(tabArgs[1].name)
        end
        return mw.html.create()
            :node(header)
            :node(tabArgs[1].content)
    end

    local tabs = mw.html.create('ul')
        :addClass('nav nav-tabs tabs tabs' .. #tabArgs)

    if not arrayAny(tabArgs, property('this')) then
        tabArgs[1].this = true
    end

    arrayForEach(tabArgs, function(tab, i)
        tabs:tag('li')
            :addClass('tab' .. i)
            :addClass(tab.this and 'active' or nil)
            :wikitext(tab.name)
    end)

    if not readBool(args['hide-showall']) and not isSingular then
        tabs:tag('li')
            :addClass('show-all')
            :wikitext('Show All')
    end

    local contents = buildContentDiv(hasContent, readBool(args['hybrid-tabs']), readBool(args['no-padding']))

    if not hasContent then
        return mw.html.create('div')
            :addClass('tabs-dynamic navigation-not-searchable')
            :attr('data-nosnippet')
            :node(tabs)
            :node(contents)
    end

    arrayForEach(tabArgs, function(tab, i)
        contents:tag('div')
            :addClass('content' .. i)
            :addClass(tab.this and 'active' or nil)
            :node(tab.content)
    end)

    return mw.html.create('div')
        :addClass('tabs-dynamic navigation-not-searchable')
        :attr('data-nosnippet')
        :node(tabs)
        :node(contents)
end

return Tabs