|
|
| Line 1: |
Line 1: |
| local Tabs = {} | | local Tabs = {} |
|
| |
|
| -- Helper functions to replace Module:Logic | | -- Helper functions |
| local function readBool(val) | | local function readBool(val) |
| if val == nil then return false end | | if val == nil then return false end |
| Line 12: |
Line 12: |
| end | | end |
|
| |
|
| local function isEmpty(val) | | local function getDisplayNameFromLink(link) |
| if val == nil then return true end | | return link:match('([^/]+)$') or link |
| 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 | | end |
|
| |
|
| -- Helper to replace Module:Operator.property | | -- Main function |
| local function property(key)
| | function Tabs.static(frame) |
| return function(obj) return obj[key] end | | local args = frame.args or {} |
| end
| | |
| | | -- Find all tabs |
| -- Simplified page link generation (replaces Module:Page)
| | local tabs = {} |
| local function makeInternalLink(_, name, link) | | local i = 1 |
| return mw.ustring.format('[[%s|%s]]', link, name) | | while args['name' .. i] or args['link' .. i] do |
| end
| | table.insert(tabs, { |
| | | name = args['name' .. i], |
| -- Main argument processor | | link = args['link' .. i], |
| local function readArguments(args, options)
| | this = (tonumber(args.This) == i) |
| local tabArgs = {} | | }) |
| local tabIndex = 1 | | i = i + 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 | | end |
| | | |
| if readBool(args.returnIfEmpty) then | | if #tabs == 0 then |
| return tabArgs | | return 'Error: No tabs defined (need at least name1 or link1)' |
| end | | end |
| | | |
| assert(#tabArgs > 0, 'You are trying to add a "Tabs" template without arguments for names nor links') | | -- Auto-set first tab as active if none specified |
| return tabArgs | | if not args.This then |
| end
| | tabs[1].this = true |
| | |
| -- 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 | | end |
| return contentDiv | | |
| end
| | -- Build HTML |
| | | local container = mw.html.create('div') |
| -- Display name extractor | | :addClass('tabs-static') |
| local function getDisplayNameFromLink(link)
| | |
| local parts = {} | | local tablist = mw.html.create('ul') |
| for part in link:gmatch('[^/]+') do
| | :addClass('nav nav-tabs tabs tabs' .. #tabs) |
| table.insert(parts, part) | | |
| end
| | for _, tab in ipairs(tabs) do |
| return parts[#parts] or link
| | local display = tab.name or getDisplayNameFromLink(tab.link) |
| end
| | local text = tab.link and ('[[' .. tab.link .. '|' .. display .. ']]') or display |
| | | |
| -- Main static tabs function
| | tablist:tag('li') |
| 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) | | :addClass(tab.this and 'active' or nil) |
| :wikitext(text) | | :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 | | end |
| | | |
| arrayForEach(tabArgs, function(tab, i)
| | return container:node(tablist) |
| 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 | | end |
|
| |
|
| return Tabs | | return Tabs |