Saltar para o conteúdo

Módulo:Sidebar

Permanently protected module
Origem: Wikipédia, a enciclopédia livre.

require('strict')
local cfg = mw.loadData('Módulo:Sidebar/configuração')

local p = {}

local getArgs = require('Módulo:Arguments').getArgs

--[[
Categoriza predefinições e módulos de chamada com um parâmetro 'style' de qualquer tipo
para rastreamento para conversão em TemplateStyles..

TODO após uma longa limpeza: captura barras laterais em outros espaços nomeados além de Predefinição e Módulo.
TODO provavelmente desejaria remover /log e /archive como o CS1 faz
]]
local function categorizeTemplatesWithInlineStyles(args)
	local title = mw.title.getCurrentTitle()
	if title.namespace ~= 10 and title.namespace ~= 828 then return '' end
	for _, pattern in ipairs (cfg.i18n.pattern.uncategorized_conversion_titles) do
		if title.text:match(pattern) then return '' end
	end

	for key, _ in pairs(args) do
		if mw.ustring.find(key, cfg.i18n.pattern.style_conversion) or key == 'width' then
			return cfg.i18n.category.conversion
		end
	end
end

--[[
Para compatibilidade com a implementação original d {{Sidebar with collapsible lists}}, que passou alguns parâmetros por meio de {{#if}} para aparar seus
espaços em branco. Isso também acionou o comportamento de nova linha automática.
]]
-- Ver ([[meta:Help:Newlines and spaces#Automatic newline]])
local function trimAndAddAutomaticNewline(s)
	s = mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1")
	if mw.ustring.find(s, '^[#*:;]') or mw.ustring.find(s, '^{|') then
		return '\n' .. s
	else
		return s
	end
end

--[[
Verifica se uma barra lateral tem uma barra lateral de subgrupo.
]]
local function hasSubgroup(s)
	if mw.ustring.find(s, cfg.i18n.pattern.subgroup) then
		return true
	else
		return false
	end
end

local function has_navbar(navbar_mode, sidebar_name)
    return navbar_mode ~= cfg.i18n.navbar_none and
        navbar_mode ~= cfg.i18n.navbar_off and
        (
            sidebar_name or
            mw.getCurrentFrame():getParent():getTitle():gsub(cfg.i18n.pattern.sandbox, '') ~=
            cfg.i18n.title_not_to_add_navbar
        )
end

local function has_list_class(args, htmlclass)
	local patterns = {
		'^' .. htmlclass .. '$',
		'%s' .. htmlclass .. '$',
		'^' .. htmlclass .. '%s',
		'%s' .. htmlclass .. '%s'
	}

	for arg, value in pairs(args) do
		if type(arg) == 'string' and mw.ustring.find(arg, 'class') then
			for _, pattern in ipairs(patterns) do
				if mw.ustring.find(args[arg] or '', pattern) then
					return true
				end
			end
		end
	end
	return false
end

-- Existem muitas classes de listas disponíveis, então adicionamos seus TemplateStyles
local function add_list_styles(args)
	local frame = mw.getCurrentFrame()
	local function add_list_templatestyles(htmlclass, templatestyles)
		if has_list_class(args, htmlclass) then
			return frame:extensionTag{
				name = 'templatestyles', args = { src = templatestyles }
			}
		else
			return ''
		end
	end

	local plainlist_styles = add_list_templatestyles('plainlist', cfg.i18n.plainlist_templatestyles)
	local hlist_styles = add_list_templatestyles('hlist', cfg.i18n.hlist_templatestyles)

	-- uma segunda solução alternativa para [[phab:T303378]]
	-- quando esse problema for corrigido, podemos realmente usar has_navbar para não emitir a
	-- tag aqui se quisermos
	if has_navbar(args.navbar, (args.name or args.nome)) and hlist_styles == '' then
		hlist_styles = frame:extensionTag{
			name = 'templatestyles', args = { src = cfg.i18n.hlist_templatestyles}
		}
	end

	-- hlist -> plainlist é o melhor esforço para preservar a antiga ordenação Common.css. [hlist_note]
	return hlist_styles .. plainlist_styles
end

-- solução alternativa [[phab:T303378]]
-- para cada argumento: encontra todos os marcadores de tira de templatestyles, insere-os em uma
-- tabela. então remove todos os marcadores de templatestyles do argumento
local function move_hiding_templatestyles(args)
	local gfind = string.gfind
	local gsub = string.gsub
	local templatestyles_markers = {}
	local strip_marker_pattern = '(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)'
	for k, arg in pairs(args) do
		for marker in gfind(arg, strip_marker_pattern) do
			table.insert(templatestyles_markers, marker)
		end
		args[k] = gsub(arg, strip_marker_pattern, '')
	end
	return templatestyles_markers
end

--[[
Função principal da barra lateral. Pega frame, args e uma collapsibleClass opcional.
A collapsibleClass é e deve ser usada apenas para barras laterais com listas
collapsíveis, como em p.collapsible.
]]
function p.sidebar(frame, args, collapsibleClass)
	if not args then args = getArgs(frame) end
	local hiding_templatestyles = table.concat(move_hiding_templatestyles(args))
	local root = mw.html.create()
	local child = (args.child or args.filha) and mw.text.trim(args.child or args.filha) == cfg.i18n.child_yes

	root = root:tag('table')
	if not child then
		root 
			:addClass(cfg.i18n.class.sidebar)
			-- força collapsibleclass a ser sidebar-collapse, caso contrário, não produzirá nada
			:addClass(collapsibleClass == cfg.i18n.class.collapse and cfg.i18n.class.collapse or nil)
			:addClass('nomobile')
			:addClass((args.float or args['flutuar'] or args['lado']) == cfg.i18n.float_none and cfg.i18n.class.float_none or nil)
			:addClass((args.float or args['flutuar'] or args['lado']) == cfg.i18n.float_left and cfg.i18n.class.float_left or nil)
			:addClass(args.wraplinks ~= cfg.i18n.wrap_true and cfg.i18n.class.wraplinks or nil)
			:addClass(args.bodyclass or args['classe-corpo'] or args.class or args.classe)
			:css('width', args.width or args.largura or nil)
			:cssText(args.bodystyle or args['estilo-corpo'] or args.style or args.estilo)

		if (args.outertitle or args['título-externo'] or args['título-exterior'] or args['cabeçalho']) then
			root
				:tag('caption')
					:addClass(cfg.i18n.class.outer_title)
					:addClass(args.outertitleclass or args['classe-título-externo'] or args['classe-título-exterior'] or args['classe-cabeçalho'])
					:cssText(args.outertitlestyle or args['estilo-título-externo'] or args['estilo-título-exterior'] or args['estilo-cabeçalho'])
					:wikitext(args.outertitle or args['título-externo'] or args['título-exterior'] or args['cabeçalho'])
		end

		if (args.topimage or args['imagem-topo'] or args['imagem2']) then
            local imageCell = root:tag('tr'):tag('td')

			imageCell
				:addClass(cfg.i18n.class.top_image)
				:addClass(args.topimageclass or args['classe-imagem-topo'] or args['classe-imagem2'])
				:cssText(args.topimagestyle or args['estilo-imagem-topo'] or args['estilo-imagem2'])
				:wikitext(args.topimage or args['imagem-topo'] or args['imagem2'])

			if (args.topcaption or args['legenda-topo'] or args['imagem_legenda2']) then
				imageCell
					:tag('div')
						:addClass(cfg.i18n.class.top_caption)
						:cssText(args.topcaptionstyle or args['estilo-legenda-topo'] or args['estilo-imagem_legenda2'])
						:wikitext(args.topcaption or args['legenda-topo'] or args['imagem_legenda2'])
			end
		end

		if (args.pretitle or args['pré-título']) then
			root
				:tag('tr')
					:tag('td')
						:addClass(args.topimage and cfg.i18n.class.pretitle_with_top_image
							or cfg.i18n.class.pretitle)
						:addClass(args.pretitleclass or args['classe-pré-título'])
						:cssText(args.basestyle or args['estilo-base'])
						:cssText(args.pretitlestyle or args['estilo-pré-título'])
						:wikitext(args.pretitle or args['pré-título'])
		end
	else
		root
			:addClass(cfg.i18n.class.subgroup)
			:addClass(args.bodyclass or args['classe-corpo'] or args.class or args.classe)
			:cssText(args.bodystyle or args['estilo-corpo'] or args.style or args.estilo)
	end

	if (args.title or args['título']) then
		if child then
			root
				:wikitext(args.title or args['título'])
		else
			root
				:tag('tr')
					:tag('th')
						:addClass((args.pretitle or args['pré-título']) and cfg.i18n.class.title_with_pretitle
							or cfg.i18n.class.title)
						:addClass(args.titleclass or args['classe-título'])
						:css('font-size', '1.5em') -- *
						:cssText(args.basestyle or args['estilo-base'])
						:cssText(args.titlestyle or args['estilo-título'])
						:wikitext(args.title or args['título'])
		end
	end

	if (args.image or args.imagem) then
		local imageCell = root:tag('tr'):tag('td')
		imageCell
			:addClass(cfg.i18n.class.image)
			:addClass(args.imageclass or args['classe-imagem'])
			:cssText(args.imagestyle or args['estilo-imagem'])
			:wikitext(args.image or args.imagem)

		if (args.caption or args.legenda or args['imagem_legenda']) then
			imageCell
				:tag('div')
					:addClass(cfg.i18n.class.caption)
					:cssText(args.captionstyle or args['estilo-legenda'] or args['estilo-imagem_legenda'])
					:wikitext(args.caption or args.legenda or args['imagem_legenda'])
		end
	end

	if (args.above or args.acima) then
		root
			:tag('tr')
				:tag('td')
					:addClass(cfg.i18n.class.above)
					:addClass(args.aboveclass or args['classe-acima'])
					:cssText(args.abovestyle or args['estilo-acima'])
					:newline() -- nova linha necessária para que os marcadores funcionem
					:wikitext(args.above or args.acima)
	end

	local rowNums = {}
	for k, v in pairs(args) do
		k = '' .. k
		local num = k:match('^heading(%d+)$') or k:match('^rótulo(%d+)$') or k:match('^content(%d+)$') or k:match('^conteúdo(%d+)$') or k:match('^dados(%d+)$')
		if num then table.insert(rowNums, tonumber(num)) end
	end
	table.sort(rowNums)
	-- remove duplicatas da lista (por exemplo, 3 será duplicado se ambos heading3
	-- e content3 forem especificados)
	for i = #rowNums, 1, -1 do
		if rowNums[i] == rowNums[i - 1] then
			table.remove(rowNums, i)
		end
	end

	for i, num in ipairs(rowNums) do
		local heading = args['heading' .. num] or args['rótulo' .. num]
		if heading then
			root
				:tag('tr')
					:tag('th')
						:addClass(cfg.i18n.class.heading)
						:addClass(args.headingclass or args['classe-rótulo'])
						:addClass(args['heading' .. num .. 'class'] or args['classe-rótulo' .. num])
						:cssText(args.basestyle or args['estilo-base'])
						:cssText(args.headingstyle or args['estilo-rótulo'])
						:cssText(args['heading' .. num .. 'style'] or args['estilo-rótulo' .. num])
						:newline()
						:wikitext(heading)
		end

		local content = args['content' .. num] or args['conteúdo' .. num] or args['dados' .. num]
		if content then
			root
				:tag('tr')
					:tag('td')
						:addClass(hasSubgroup(content) and cfg.i18n.class.content_with_subgroup
							or cfg.i18n.class.content)
						:addClass(args.contentclass or args['classe-conteúdo'] or args['classe-dados'])
						:addClass(args['content' .. num .. 'class'] or args['classe-conteúdo' .. num] or args['classe-dados' .. num])
						:cssText(args.contentstyle or args['estilo-conteúdo'] or args['estilo-dados'])
						:cssText(args['content' .. num .. 'style'] or args['estilo-conteúdo' .. num] or args['estilo-dados' .. num])
						:newline()
						:wikitext(content)
						:done()
						-- Sem uma quebra de linha após </td>, uma lista aninhada como
						-- "* {{hlist| ...}}" não é analisada corretamente.
					:newline()
		end
	end

	if (args.below or args.abaixo) then
		root
			:tag('tr')
				:tag('td')
					:addClass(cfg.i18n.class.below)
					:addClass(args.belowclass or args['classe-abaixo'])
					:cssText(args.belowstyle or args['estilo-abaixo'])
					:newline()
					:wikitext(args.below or args.abaixo)
	end
	if not child and has_navbar(args.navbar, (args.name or args.nome)) then
		root
			:tag('tr')
				:tag('td')
					:addClass(cfg.i18n.class.navbar)
					:cssText(args.navbarstyle or args['estilo-navbar'])
					:wikitext(require('Módulo:Navbar')._navbar{
						(args.name or args.nome),
						mini = 1,
						fontstyle = args.navbarfontstyle or args['estilo-fonte-navbar']
					})
	end

	local base_templatestyles = frame:extensionTag{
		name = 'templatestyles', args = { src = cfg.i18n.templatestyles }
	}

	local templatestyles = ''
	if args['templatestyles'] and args['templatestyles'] ~= '' then
		templatestyles = frame:extensionTag{
			name = 'templatestyles', args = { src = args['templatestyles'] }
		}
	end

	local child_templatestyles = ''
	if args['child templatestyles'] and args['child templatestyles'] ~= '' then
		child_templatestyles = frame:extensionTag{
			name = 'templatestyles', args = { src = args['child templatestyles'] }
		}
	end

	local grandchild_templatestyles = ''
	if args['grandchild templatestyles'] and args['grandchild templatestyles'] ~= '' then
		grandchild_templatestyles = frame:extensionTag{
			name = 'templatestyles', args = { src = args['grandchild templatestyles'] }
		}
	end

	return table.concat({
		add_list_styles(args), -- ver [hlist_note] acima sobre a ordenação 
		base_templatestyles,
		templatestyles,
		child_templatestyles,
		grandchild_templatestyles,
		hiding_templatestyles,
		tostring(root),
		(child and cfg.i18n.category.child or ''),
		categorizeTemplatesWithInlineStyles(args)
	})
end

local function list_title(args, is_centered_list_titles, num)
	local title_text = trimAndAddAutomaticNewline(args['list' .. num .. 'title'] or args['título-lista' .. num]
		or cfg.i18n.default_list_title)

	local title
	if is_centered_list_titles then
		-- recolhível pode ser complicado, então fornece alguma CSS/HTML para dar suporte
		title = mw.html.create('div')
			:addClass(cfg.i18n.class.list_title_centered)
			:wikitext(title_text)
	else
		title = mw.html.create()
			:wikitext(title_text)
	end

	local title_container = mw.html.create('div')
		:addClass(cfg.i18n.class.list_title)
		-- não /precisa/ de uma listnumtitleclass porque você pode fazer
		-- .templateclass .listnumclass .sidebar-list-title
		:addClass(args.listtitleclass or args['classe-título-lista'])
		:cssText(args.basestyle or args['estilo-base'])
		:cssText(args.listtitlestyle or args['estilo-título-lista'])
		:cssText('color: var(--color-base)')
		:cssText(args['list' .. num .. 'titlestyle'] or args['estilo-título-lista' .. num])
		:node(title)
		:done()

	return title_container
end

--[[Ponto de entrada principal para barra lateral com listas recolhíveis.
Faz o trabalho de criar as próprias listas recolhíveis e incluí-las
nos args.
]]
function p.collapsible(frame)
	local args = getArgs(frame)
	if not (args.name or args.nome) and
		frame:getParent():getTitle():gsub(cfg.i18n.pattern.collapse_sandbox, '') ==
		cfg.i18n.collapse_title_not_to_add_navbar then
		args.navbar = cfg.i18n.navbar_none
	end

	local contentArgs = {}

	local is_centered_list_titles = false
	if args['centered list titles'] and args['centered list titles'] ~= '' then
		is_centered_list_titles = true
	end

	for k, v in pairs(args) do
		local num = string.match(k, '^list(%d+)$') or string.match(k, '^lista(%d+)$') or string.match(k, '^lista(%d+)-nome')
		if num then
			local expand = args.expanded and
				(args.expanded == 'all' or args.expanded == 'tudo'
				or args.expanded == 'todo' or args.expanded == 'toda'
				or args.expanded == 'todos' or args.expanded == 'todas'
				or args.expanded == (args['list' .. num .. 'name'] or args['lista' .. num .. 'nome'] or args['lista' .. num .. '-nome'])) or args.expandir and
				(args.expandir == 'all' or args.expandir == 'tudo'
				or args.expandir == 'todo' or args.expandir == 'toda'
				or args.expandir == 'todos' or args.expandir == 'todas'
				or args.expandir == (args['list' .. num .. 'name'] or args['lista' .. num .. 'nome'] or args['lista' .. num .. '-nome'])) or args.expandida and
				(args.expandida == 'all' or args.expandida == 'tudo'
				or args.expandida == 'todo' or args.expandida == 'toda'
				or args.expandida == 'todos' or args.expandida == 'todas'
				or args.expandida == (args['list' .. num .. 'name'] or args['lista' .. num .. 'nome'] or args['lista' .. num .. '-nome']))
			local row = mw.html.create('div')
			row
				:addClass(cfg.i18n.class.list)
				:addClass('mw-collapsible')
				:addClass((not expand) and 'mw-collapsed' or nil)
				:addClass(args['list' .. num .. 'class'] or args['classe-lista' .. num])
				:cssText(args.listframestyle or args['estilo-quadro-lista'])
				:cssText(args['list' .. num .. 'framestyle'] or args['estilo-quadro-lista' .. num])
				:node(list_title(args, is_centered_list_titles, num))
				:tag('div')
					:addClass(cfg.i18n.class.list_content)
					:addClass('mw-collapsible-content')
					:addClass(args.listclass or args['classe-lista'])
					:cssText(args.liststyle or args['estilo-lista'])
					:cssText(args['list' .. num .. 'style'] or args['estilo-lista' .. num])
					:wikitext(trimAndAddAutomaticNewline(args['list' .. num] or args['lista' .. num]))

			
			contentArgs['content' .. num] = tostring(row)
		end
	end

	for k, v in pairs(contentArgs) do
		args[k] = v
	end

	return p.sidebar(frame, args, cfg.i18n.class.collapse)
end

return p