July 25, 2020

👭 Knight Challenge #11 👬

Want to try your hand at these challenges? There's a couple of things you can do!
From writing, to research, to images, find your preferred way to contribute with our eleventh theme: Couples!

Latest Announcements

Difference between revisions of "Module:UtilsLayout/Tabs"

From Zelda Wiki, the Zelda encyclopedia
Jump to: navigation, search
(adding ability to specify tab content width/height in pixels, for Template:Media)
Line 68: Line 68:
 
 
 
if align then
 
if align then
tabContents:css("text-align", align) -- TODO: add a class here instead of inline CSS
+
tabContents:addClass("tabcontents--align-x-"..align)
 
end
 
end
 
if alignVertical then
 
 
tabContents:addClass("tabcontents--align-y-"..alignVertical)
if alignVertical == "center" then
 
tabContents:addClass("tabcontents--align-y-center")
 
elseif alignVertical == "bottom" then
 
tabContents:addClass("tabcontents--align-y-bottom")
 
 
end
 
end
 
 

Revision as of 11:01, 19 September 2020

Contents

tabs

tabs(data, [options])

Parameters
  • data
    label
    Button text for the tab.
    [tooltip]
    Tooltip for the tab button
    content
    Content for the tab.
  • [options]
    [default=1]
    Index of default tab.
    [collapse]
    If truthy, tabs will not be rendered if there is only one tab. The content of that tab will simply be rendered instead.
    [format="top"]
    If top, the tabs are placed above their content. If bottom, then the opposite.
    [stretch]
    If true, then tabs will stretch to fill the available space in their container.
    [columns]
    If specified, the tabs will attempt to arrange themselves in N columns of equal width. This option is not compatible with stretch.
    [align="left"]
    Horizontal alignment for tabs and their content.
    [alignVertical="top"]
    Vertical alignment of tab contents with respect to the tab container. Useful only alonside fixedHeight.
    [fixedContentWidth]
    Width for the tab container in px. Or, if set to true, the tab container will assume the width of the largest tab. By default, the tab container assumes the width of the current tab.
    [fixedContentHeight]
    Height for the tab container in px. Or, if set to true, the tab container will assume the height of the largest tab. By default, the tab container assumes the height of the current tab.
Returns
  • HTML markup rendering tabs.
Examples
InputResult
tabs({
  {
    content = "Content1",
    label = "Tab1",
  },
  {
    content = "Content2",
    label = "Tab2",
  },
})
Tab1Tab2
Content1
Content2
tabs(
  {
    {
      content = "Content1",
      label = "Tab1",
    },
    {
      content = "Content2",
      label = "Tab2",
    },
  },
  { stretch = true }
)
Tab1Tab2
Content1
Content2
tabs(
  {
    {
      tooltip = "This is the first tab.",
      content = "Content1",
      label = "Tab1",
    },
    {
      tooltip = "This is the second tab.",
      content = "Content2",
      label = "Tab2",
    },
    {
      tooltip = "This is the third tab.",
      content = "Content3",
      label = "Tab3",
    },
  },
  {
    align = "center",
    format = "bottom",
    default = 2,
  }
)
Content1
Content2
Content3
Tab1Tab2Tab3
Tabs display even for a single tab unless collapse is set to true.
tabs({
  {
    content = "Content",
    label = "Single Tab",
  },
})
Single Tab
Content
tabs(
  {
    {
      content = "Content",
      label = "Single Tab",
    },
  },
  { collapse = true }
)
Content
fixedContentWidth and fixedContentHeight determine how the overall tab container is sized.
tabs({
  {
    content = "meep",
    label = "Small Tab",
  },
  {
    content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep",
    label = "Wide Tab",
  },
  {
    content = "m\ne\ne\ne\ne\np",
    label = "Tall tab",
  },
})
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep
m

e e e e

p
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  { fixedContentWidth = true }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeep
m

e e e e

p
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  { fixedContentHeight = true }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeep
m

e e e e

p
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  {
    alignVertical = "center",
    fixedContentWidth = true,
    fixedContentHeight = true,
  }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeep
m

e e e e

p
tabs(
  {
    {
      content = "meep",
      label = "Small Tab",
    },
    {
      content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep",
      label = "Wide Tab",
    },
    {
      content = "m\ne\ne\ne\ne\np",
      label = "Tall tab",
    },
  },
  {
    alignVertical = "center",
    fixedContentWidth = 80,
    fixedContentHeight = 80,
  }
)
Small TabWide TabTall tab
meep
meeeeeeeeeeeeeeeeeeeeeeeeeeep
m

e e e e

p

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.." - 2*"..(columns-1).."px)" -- the subtraction is to account for tab margins
			})
		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:addClass("tabcontents--align-x-"..align)
	end
	if alignVertical then
		tabContents:addClass("tabcontents--align-y-"..alignVertical)
	end
	
	if fixedContentWidth then
		tabContents:addClass("tabcontents--fixed-width")
		if type(fixedContentWidth) == "number" then
			tabContents:css("width", fixedContentWidth .. "px")
		end
	end
	if fixedContentHeight then
		tabContents:addClass("tabcontents--fixed-height")
		if type(fixedContentHeight) == "number" then
			tabContents:css("height", fixedContentHeight .. "px")
		end
	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",
					oneOf = {
						{ type = "boolean" },
						{ type = "number" },
					},
					desc = "Width for the tab container in <code>px</code>. Or, if set to <code>true</code>, the tab container will  assume the width of the largest tab. By default, the tab container assumes the width of the current tab."
				},
				{
					name = "fixedContentHeight",
					oneOf = {
						{ type = "boolean" },
						{ type = "number" },
					},
					desc = "Height for the tab container in <code>px</code>. Or, if set to <code>true</code>, the tab container will  assume the height of the largest tab. By default, the tab container assumes the height 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",
					},
 				},
			},
			{
				args = {
					{
						{ label = "Small Tab", content = "meep" },
						{ label = "Wide Tab", content = "meeeeeeeeeeeeeeeeeeeeeeeeeeep" },
						{ label = "Tall tab", content = "m\ne\ne\ne\ne\np" },
					},
					{ 
						fixedContentWidth = 80,
						fixedContentHeight = 80,
						alignVertical = "center",
					},
 				},
			},
		},
	},
}

return p