Module:UtilsLayout/Tabs
Jump to navigation
Jump to search
Lua error in Module:Documentation/Module at line 351: attempt to call field 'Documentation' (a table value).
local p = {}
local h = {}
function p.tabs(data, options)
local options = options or {}
local format = options.format or "top"
local align = options.align or "left"
local alignVertical = options.alignVertical or "top"
local columns = options.columns
local collapse = options.collapse
local defaultTab = options.default or 1
local stretch = options.stretch
local fixedContentWidth = options.fixedContentWidth
local fixedContentHeight = options.fixedContentHeight
if #data == 1 and collapse then
return data[1].content
end
local tabContainer = h.tabContainer(data, defaultTab, format, align, columns, stretch)
local tabContents = h.tabContents(data, defaultTab, align, alignVertical, fixedContentWidth, fixedContentHeight)
local html = mw.html.create("div")
if format == "top" then
html:node(tabContainer)
:node(tabContents)
else
html:node(tabContents)
:node(tabContainer)
end
return tostring(html)
end
function h.tabContainer(data, defaultTab, format, align, columns, stretch)
local tabContainer = mw.html.create("div"):addClass("tabcontainer tabcontainer-" .. format)
if align then
tabContainer:addClass("tabcontainer--"..align)
end
if stretch then
tabContainer:addClass("tabcontainer--stretch")
end
if columns then
tabContainer:addClass("tabcontainer--columns")
end
for i, tabData in ipairs(data) do
local tab = mw.html.create("span")
:addClass("tab explain")
:attr("title", tabData.tooltip)
:wikitext(tabData.label)
if i == defaultTab then
tab:addClass("active")
end
if columns then
tab:css({
["max-width"] = "calc(100%/"..columns.." - 3*"..columns.."px)"
})
end
tabContainer:node(tab)
end
return tabContainer
end
function h.tabContents(data, defaultTab, align, alignVertical, fixedContentWidth, fixedContentHeight)
local tabContents = mw.html.create("div")
:addClass("tabcontents")
if align then
tabContents:css("text-align", align) -- TODO: add a class here instead of inline CSS
end
if alignVertical == "center" then
tabContents:addClass("content--align-y-center")
elseif alignVertical == "bottom" then
tabContents:addClass("content--align-y-bottom")
end
if fixedContentWidth then
tabContents:addClass("tabcontents--fixed-width")
end
if fixedContentHeight then
tabContents:addClass("tabcontents--fixed-height")
end
for i, tabData in ipairs(data) do
local content = mw.html.create("div")
:addClass("content")
:wikitext(tabData.content)
if i == defaultTab then
content:addClass("content--active")
end
tabContents:node(content)
end
return tabContents
end
p.Schemas = {
tabs = {
data = {
type = "array",
required = true,
items = {
type = "record",
properties = {
{
name = "label",
type = "string",
required = true,
desc = "Button text for the tab."
},
{
name = "tooltip",
type = "string",
desc = "Tooltip for the tab button",
},
{
name = "content",
type = "string",
required = true,
desc = "Content for the tab.",
},
}
}
},
options = {
type = "record",
properties = {
{
name = "default",
type = "number",
default = 1,
desc = "Index of default tab.",
},
{
name = "collapse",
type = "boolean",
desc = "If truthy, tabs will not be rendered if there is only one tab. The content of that tab will simply be rendered instead."
},
{
name = "format",
type = "string",
enum = {"top", "bottom"},
default = mw.dumpObject("top"),
desc = "If <code>top</code>, the tabs are placed above their content. If <code>bottom</code>, then the opposite."
},
{
name = "stretch",
type = "boolean",
desc = "If true, then tabs will stretch to fill the available space in their container.",
},
{
name = "columns",
type = "number",
desc = "If specified, the tabs will attempt to arrange themselves in N columns of equal width. This option is not compatible with <code>stretch</code>."
},
{
name = "align",
type = "string",
enum = {"left", "center", "right"},
default = mw.dumpObject("left"),
desc = "Horizontal alignment for tabs and their content.",
},
{
name = "alignVertical",
type = "string",
enum = {"top", "center", "bottom"},
default = mw.dumpObject("top"),
desc = "Vertical alignment of tab contents with respect to the tab container. Useful only alonside <code>fixedHeight</code>."
},
{
name = "fixedContentWidth",
type = "boolean",
desc = "If truthy, the tab container will always assume the width of the largest tab (as opposed to the width of the current tab)."
},
{
name = "fixedContentHeight",
type = "boolean",
desc = "If truthy, the tab container will always assume the height of the tallest tab (as opposed to that of the current tab).",
}
}
},
}
}
p.Documentation = {
tabs = {
params = {"data", "options"},
returns = "HTML markup rendering tabs.",
cases = {
resultOnly = true,
{
args = {
{
{
label = "Tab1",
content = "Content1",
},
{
label = "Tab2",
content = "Content2"
},
},
}
},
{
args = {
{
{
label = "Tab1",
content = "Content1",
},
{
label = "Tab2",
content = "Content2"
},
},
{
stretch = true,
},
},
},
{
args = {
{
{
label = "Tab1",
tooltip = "This is the first tab.",
content = "Content1"
},
{
label = "Tab2",
tooltip = "This is the second tab.",
content = "Content2"
},
{
label = "Tab3",
tooltip = "This is the third tab.",
content = "Content3"
}
},
{
format = "bottom",
align = "center",
default = 2,
}
}
},
{
desc = "Tabs display even for a single tab unless <code>collapse</code> is set to true.",
args = {
{{ label = "Single Tab", content = "Content" }}
}
},
{
args = {
{{ label = "Single Tab", content = "Content" }},
{ collapse = true }
}
},
{
desc = "<code>fixedContentWidth</code> and <code>fixedContentHeight</code> determine how the overall tab container is sized.",
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
},
},
{
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{ fixedContentWidth = true },
},
},
{
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{ fixedContentHeight = true },
},
},
{
args = {
{
{ label = "Small Tab", content = "meep" },
{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
},
{
fixedContentWidth = true,
fixedContentHeight = true,
alignVertical = "center",
},
},
},
},
},
}
return p