Module:Tabs

From TwogPedia
Revision as of 11:47, 12 September 2022 by Couchor (talk | contribs)

Documentation for this module may be created at Module:Tabs/doc

local getArgs = require('Module:Arguments').getArgs

local Tabs = {}

function Tabs.static(frame)
	local args = getArgs(frame)
	local tabCount = Tabs.number_of_tabs(args)
	local this = tonumber(args['This']) or Tabs.computeThis(args, tabCount)
	local this2 = tonumber(args['This2'])

	local outerDiv = mw.html.create('div')
		:addClass('tabs-static')
		:attr('data-nosnippet', '')

	local ul = outerDiv:tag('ul')
		:attr('class', 'nav nav-tabs navigation-not-searchable tabs tabs' .. tabCount)

	for i = 1, tabCount do
		local link = args['link' .. i]
		local tabName = args['name' .. i]

		local text
		if link ~= nil then
			-- If name is unspecified, then use the last link segment as the name
			tabName = tabName or Tabs.computeLastSegment(link)
			text = '[[' .. link .. '|' .. tabName .. ']]'
		else
			text = tabName
		end

		local li = ul:tag('li')
			:wikitext(text)

		if (i == this) or (i == this2) then
			li:addClass('active')
		end
	end

	-- optionally add more tab bars beneath
	local extra = ''
	if this and args['tabs' .. this] ~= nil then
		extra = args['tabs' .. this]
	end

	return tostring(outerDiv) .. extra
end

function Tabs.computeThis(args, tabCount)
	local fullPageName = mw.title.getCurrentTitle().prefixedText
	local this = nil

	-- Finds the link that is a prefix of the current page. If there are more than one, choose the longest, then first.
	-- For example, if the current page is ab/cd/e3, then among
	--   ab/cd/e1
	--   ab/cd/e2
	--   ab/cd/e
	--   ab/cd
	--   ab/cg
	--   ab
	-- it will pick ab/cd.
	local maxLinkLength = -1
	for i = 1, tabCount do
		local link = args['link' .. i]

		if link ~= nil then
			link = mw.ustring.gsub(link, '_', ' ')

			local linkLength = mw.ustring.len(link)
			local charAfter = mw.ustring.sub(fullPageName, linkLength + 1, linkLength + 1)
			if
				mw.ustring.sub(fullPageName, 1, linkLength) == link
					-- Prefix must be aligned at '/' boundaries
					and (charAfter == '/' or charAfter == '')
					and linkLength > maxLinkLength then
				maxLinkLength = linkLength
				this = i
			end
		end
	end

	return this
end

-- Computes the number of tabs requested
function Tabs.number_of_tabs(args)
	mw.log(args)
	mw.logObject(args)
	args = args or {}
	local i = 0
	
	while args['name' .. (i + 1)] ~= nil or args['link' .. (i + 1)] ~= nil do
		i = i + 1
	end
	if i == 0 then
		error('You are trying to add a "Tabs" template without arguments for names nor links')
	end
	return i
end

-- Computes the last segment of a page name
-- e.g. Tabs.computeLastSegment('abc/def/ghi') -> 'ghi'
function Tabs.computeLastSegment(pageName)
	local start = 1
	while true do
		local nextStart, nextEnd = mw.ustring.find(pageName, '/', start)
		if nextStart == nil then
			return mw.ustring.sub(pageName, start)
		end

		start = nextEnd + 1
	end
end

--[[
Creates dynamic tabs.

Entry point of Template:Tabs dynamic
]]
function Tabs.dynamic(args)
	local this = tonumber(args['This']) or 1
	local hideShowAll = args['hide-showall']
	local tabs = Tabs.number_of_tabs(args)

	local list = '\n<ul class="nav nav-tabs tabs tabs' .. tabs .. '">'
	local innerDiv = '\n<div class="tabs-content wiki-bordercolor-light">'

	local i = 1
	while(i <= tabs) do
		local text = args['name' .. i]
		local li = '\n<li class="tab' .. i .. ' ' ..
			((this == i) and 'active' or '') ..
			'>' .. text .. '</li>'
		list = list .. li

		local content = args['content' .. i]
		if content ~= nil then
			local contentDiv = '\n<div class="content' .. i ..
				((this == i) and ' active' or '') .. '">' ..
				'\n' .. content .. '</div>'
			innerDiv = innerDiv .. contentDiv
		end
		i = i + 1
	end

	if (hideShowAll == nil) then
		local li = '<li class="show-all">Show All</li>'
		list = list .. li
	end
	list = list .. '\n</ul>'

	local outerDiv = '<div class="tabs-dynamic">'
	outerDiv = outerDiv .. list .. innerDiv

	if args['content1'] ~= nil then
		outerDiv = outerDiv .. '\n</div>\n</div>' -- close off both inner and outer
	end

	return outerDiv

end

return Tabs