Modul:Header structure

--[=[
This is a module to implement logic for header templates
]=]

require('strict')

local p = {} --p stands for package

local getArgs = require('Module:Arguments').getArgs
local plain_sister = require('Module:Plain sister')._plain_sister

-- return true if any value in list is not nil or empty in args
-- (nil means not present; empty string is not nil)
local function has_any_arg(args, list)
	for k, v in pairs(list) do
		if args[v] ~= nil then
			return true
		end
	end
	return false
end

--[=[
Construct the main block
]=]
local function construct_main_block(args, prefix)
	-- header and tracking categories
	local main_div = mw.html.create('div')
		:addClass('wst-header-mainblock')
		:addClass(prefix .. '-mainblock')

	-- If an extra main class was provided, add it
	-- TODO: Is this used? Is it needed?
	if args.main_class ~= nil and args.main_class ~= "" then
		main_div:addClass(args.main_class)
	end

	-- If an extra main id was provided, add it
	-- TODO: Is this used? Is it needed?
	if args.main_id then
		main_div:attr('id', args.main_id)
	end

	-- "Previous" field
	local prev_div = main_div:tag('div')
		:addClass('wst-header-back')
		:addClass('searchaux')
		:addClass(prefix .. '-back')
	:tag('div'):addClass('wst-header-back-arrow'):wikitext('←')
		:done()
	:tag('div'):addClass('wst-header-back-link'):wikitext(args['previous'])
		:done()
	if args['previous'] == nil or args['previous'] == "" then
		prev_div:addClass('wst-header-nav-empty')
	end
	
	-- The central cell
	local center_div = main_div:tag('div')
		:addClass('wst-header-central-cell')
		:addClass(prefix .. '-central-cell')
	
	-- Special case to manage exceptional formatting in disambiguation-like
	-- pages; not otherwise documented
	local pretitle = ''
	if args.pretitle then
		local br = '<br/>'
		if not args.main_title or args.main_title == '' then
			br = ''
		end
		
		center_div:tag('span')
			:addClass('wst-header-pretitle')
			:wikitext(args.pretitle .. br)
	end
	
	center_div:tag('span')
		:addClass('wst-header-title')
		:addClass(prefix .. '-title')
		:wikitext(args.main_title or '')

	-- "Next" field
	local next_div = main_div:tag('div')
		:addClass('wst-header-forward')
		:addClass('searchaux')
		:addClass(prefix .. '-forward')
	:tag('div'):addClass('wst-header-forward-link'):wikitext(args['next'])
		:done()
	:tag('div'):addClass('wst-header-forward-arrow'):wikitext('→')
		:done()
	if args['next'] == nil or args['next'] == "" then
		next_div:addClass('wst-header-nav-empty')
	end

	return tostring(main_div)
end

--[=[
Construct the notes block
]=]
local function construct_notes_block(args, prefix)
	local main_div = mw.html.create('div')
		:addClass('wst-header-notes')
		:addClass('header_notes')
		:addClass('searchaux')
		:addClass(prefix .. '-notes')

	-- If an extra main class was provided, add it
	-- TODO: Is this used? Is it needed?
	if args.notes_class ~= nil and args.notes_class ~= "" then
		main_div:addClass(args.notes_class)
	end

	-- If an extra main id was provided, add it
	-- TODO: Is this used? Is it needed?
	if args.notes_id then
		main_div:attr('id', args.notes_id)
	end
	
	-- Left-floated content has to come first, or it may float below the sisters.
	local notes_left_content = ''
	if args.notes_left_content then
		local notes_left_content_div = mw.html.create('div')
			:addClass('wst-header-left')
			:addClass('header_notes_left_content')
			:addClass(prefix .. '-left')
			:wikitext(args.notes_left_content)
		notes_left_content = tostring(notes_left_content_div)
	end
	
	local shortcut = ''
	if args.shortcut then
		shortcut = mw.getCurrentFrame():expandTemplate {
			title = 'shortcut',
			args = {args.shortcut}
		}
	end
	
	local notes_content = ''
	if args.notes then
		args.notes = mw.getCurrentFrame():preprocess(args.notes)
		-- linebreaks are so notes get paragraph formatting
		local notes_content_div = mw.html.create('div')
			:addClass('wst-header-content')
			:addClass('header_notes_content')
			:addClass('wst-header-notes-content')
			:addClass(prefix .. '-notes-content')
			:wikitext('\n' .. args.notes .. '\n')
		notes_content = tostring(notes_content_div)
	end
	
	local wdid = mw.wikibase.getEntityIdForCurrentPage()
	local sister = plain_sister(args)
	
	if not sister and not args.notes and not args.notes_left_content then
		return ''
	end
	
	return tostring(main_div:wikitext(notes_left_content .. (sister or '') .. shortcut .. notes_content))
end

--[=[
Construct header
]=]

function p.construct_header(args)
	-- Make sure the main identifying class for the client template is set
	local prefix = "wst-unknown"
	if args.template ~= nil and args.template ~= "" then
		prefix = "wst-" .. args.template
	end

	local headerContainer = mw.html.create('div')
		:addClass("ws-header")
		:addClass("wst-header-structure")
		:addClass(prefix)

	-- header_class from client modules, class from individual uses
	if args.header_class then
		headerContainer:addClass(args.header_class)
	end
	if args.class then
		headerContainer:addClass(args.class)
	end
	
	headerContainer:wikitext(table.concat({
		(args.pre_main or ''),
		construct_main_block(args, prefix),
		construct_notes_block(args, prefix),
		(args.post_notes or '')
	}))
	
	local stylesheet = mw.getCurrentFrame():extensionTag('templatestyles', '', {src = 'Header structure/styles.css'})
	
	return stylesheet .. (args.pre_container or '') .. tostring(headerContainer)
end

function p.header_structure(frame)
	return p.construct_header(getArgs(frame))
end

return p