Jump to content

Module:Contents topic list

From Wikipedia, the free encyclopedia

require('strict')

local getArgs = require('Module:Arguments').getArgs
local p = {}

-- Close <li> and <ul> elements enclosing deeper depths
local function closePending(toClose, depth)
	local out = ''
	
	while #toClose > 0 and (toClose[#toClose].depth >= depth or depth == 0) do
		out = out .. toClose[#toClose].close
		table.remove(toClose, #toClose)
	end
	
	return out
end

function p.main(frame)
	local args = getArgs(frame)
	local wikitext = frame:preprocess(args[1])
	local items = {}
	local out = ''
	
	for indent, item in wikitext:gmatch('(**) *([^\n]*)\n') do
	    table.insert(items, {#indent, item})
	end
	
	-- Match the last line
	local lastIndent, lastItem = wikitext:match('(**) *([^\n]*)$')
	table.insert(items, {#lastIndent, lastItem})
	
	-- Elements that are currently open
	local toClose = {}
	-- Lowest depth of parent that forces all <li>s to be inline
	local forcedInline = math.huge

	for i, item in pairs(items) do
		local level, text = unpack(item)
		out = out .. closePending(toClose, level)
		
		if level == 0 then
			-- Just output 
			out = out .. text .. '\n'
		else
			-- Create a new list if needed
			if #toClose == 0 or toClose[#toClose].type ~= 'ul' then
				out = out .. (forcedInline <= level and '<ul class="content-inline-ul">' or '<ul>')
				
				toClose[#toClose + 1] = {
					depth = level - 1,
					type = 'ul',
					close = '</ul>' .. (level == 1 and '\n' or '')
				}
			end
			
			-- Went up a level, discard forced inline and rest block
			if level <= forcedInline then
				forcedInline = math.huge
			end
			
			if text:match('KEEP%-INLINE$') ~= nil then
				-- Line is marked by {{Keep inline}}
				out = out .. '<li>' .. text:gsub(' *KEEP%-INLINE$', '')
				forcedInline = math.min(level, forcedInline)
			elseif forcedInline < level then
				-- Inline forced
				out = out .. '<li>' .. text
			elseif i < #items and items[i + 1][1] > level then
				-- Next item is deeper
				-- Remove ":" if first item is block-level
				out = out:gsub("&#58; '''''<ul>$", "'''''<ul>")
				out = out .. '<li class="content-sublist">' .. "'''''" .. text .. "&#58; '''''"
				-- Treat remaining items in this list as block-level
				toClose[#toClose].restBlock = true
			elseif toClose[#toClose].restBlock then
				-- Rest of list should be block level
				out = out .. '<li class="content-sublist">' .. "'''''" .. text .. "'''''"
			else
				-- Normal list item
				out = out .. '<li>' .. text
			end
			
			toClose[#toClose + 1] = {
				depth = level,
				type = 'li',
				close = '</li>'
			}
		end
	end
	
	out = out .. closePending(toClose, 0)
	
	return '<div class="content-list">\n' .. out  .. '</div>' .. frame:extensionTag{
		name = 'templatestyles', args = { src = 'Template:Contents topic list/styles.css' }
	}
end

return p