Module:Sandbox/LVLGive feedback
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