More actions
Documentation for this module can be edited at Module:Tabs/doc.
{{#invoke:Tabs|main |name= |containerclass= forceland (force the tabs to be laid out horizontally above the content) forceport (force the tabs to be laid out vertically to the left of the content) |containerstyle= |tabstyle= |tab1= |tabclass1= |tabstyle1= |content1= |contentclass1= |contentstyle1= }}
Tabs can be nested (see BBCP and BBCF tabs below).
--------------------------------------------------------------------------------
--Tab class
--------------------------------------------------------------------------------
local Tab = {}
Tab.__index = Tab
Tab.fields = {
number = true,
tabclass = true,
tabstyle = true,
contentclass = true,
contentstyle = true,
content = true,
tab = true,
}
function Tab.new(data)
local self = setmetatable({}, Tab)
for field in pairs(Tab.fields) do
self[field] = data[field] or ''
end
self.number = assert(tonumber(self.number))
return self
end
function Tab:getTabName()
return self.tab
end
function Tab:getTabClass()
return self.tabclass
end
function Tab:getTabStyle()
return self.tabstyle
end
function Tab:getContentClass()
return self.contentclass
end
function Tab:getContentStyle()
return self.contentstyle
end
function Tab:getContent()
return self.content
end
--------------------------------------------------------------------------------
-- Tabs class
--------------------------------------------------------------------------------
local Tabs = {}
Tabs.__index = Tabs
Tabs.fields = {
name = true,
containerclass = true,
containerstyle = true,
ulstyle = true,
tabstyle = true,
tabclass = true,
contentclass = true,
contentstyle = true
}
function Tabs.new(data)
local self = setmetatable({}, Tabs)
-- add properties
for field in pairs(Tabs.fields) do
self[field] = data[field] or ''
end
-- make tab objects
self.tabs = {}
for i, tabData in ipairs(data.tabs or {}) do
table.insert(self.tabs, Tab.new(tabData))
end
return self
end
function Tabs:__tostring()
-- Root of the output
local root = mw.html.create()
-- Wrapper
div = root:tag('div')
div
:attr('id',"tabs-" .. self.name)
:attr('class','tabdiv')
:addClass(self.containerclass)
:cssText(self.containerstyle)
-- Tab List
local ul = div:tag('ul')
ul:cssText(self.ulstyle)
for i, tab in ipairs(self.tabs) do
local tabID = self.name .. "tab" .. i
-- Create Tab
li = ul:tag('li')
li
:attr('id',self.name .. "tabtag" .. i)
:addClass(self.tabclass)
:addClass(tab:getTabClass())
:cssText(self.tabstyle .. tab:getTabStyle())
:wikitext('[[#' .. tabID .. '|' .. tab:getTabName() .. ']]')
-- Create Content
local contentDiv = div:tag('div')
contentDiv
:attr('id',tabID)
:addClass(self.contentclass)
:addClass(tab:getContentClass())
:cssText(self.contentstyle .. tab:getContentStyle())
:wikitext(tab:getContent())
end
return root
end
--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------
local p = {}
function p._main(args)
-- Process numerical args so that we can iterate through them.
local data, tabs = {}, {}
for k, v in pairs(args) do
if type(k) == 'string' then
local prefix, num = k:match('^(%D.-)(%d+)$')
if prefix and Tab.fields[prefix] and (num == '0' or num:sub(1, 1) ~= '0') then
-- Allow numbers like 0, 1, 2 ..., but not 00, 01, 02...,
-- 000, 001, 002... etc.
num = tonumber(num)
tabs[num] = tabs[num] or {}
tabs[num][prefix] = v
else
data[k] = v
end
end
end
data.tabs = (function (t)
-- Compress sparse array
local ret = {}
for num, tabData in pairs(t) do
tabData.number = num
table.insert(ret, tabData)
end
table.sort(ret, function (t1, t2)
return t1.number < t2.number
end)
return ret
end)(tabs)
return tostring(Tabs.new(data))
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame)
return p._main(args)
end
return p