Module:Header

--[=[ This is a module to implement logic for the template

It doesn't do everything yet, but over time it can accrete functions from the template, which will become simpler and simpler until it's just an invoke.

Not implemented yet: * Categories (deprecated anyway) * Subpage checking ]=]

local p = {} --p stands for package

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

-- get the param_override or param parameter in that order -- nil if neither is there function get_arg_or_override(args, param) if args["override_" .. param] then return args["override_" .. param] elseif args[param] then return args[param] end return nil end

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

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

--[=[ Return '1' if the template has missing required parameters ]=] function p.has_missing_params(frame) local args = getArgs(frame, {		removeBlanks = false	}) local required_args = {'title', 'section', 'author', 'previous', 'next', 'notes'} if any_arg_nil(args, required_args) then return '1' end return '' end

-- Place each value from a table of IDs:values into the given parent element function append_mf_values(parent, values) for k,v in pairs(values) do		parent:tag("span") :attr("id", k)			:wikitext(v) end end

-- Create the Microformat wrapper div function construct_mf_wrapper(args) local mf_div = mw.html.create("div") mf_div:addClass("ws-noexport") :attr("id", "ws-data") :css({			speak = "none"		}) -- hide the microformat unless it's overriden if not (args["show_microformat"] and yesno(args['show_microformat'])) then mf_div:css("display", "none") end return mf_div end

-- Collect all the values of microformat data from the arguments provided -- Returns a table of microformat ID:contents. function collect_mf_data(args) -- collect the MF values here local mf = {};

mf["ws-article-id"] = mw.title.getCurrentTitle.id 	-- add the title if args["title"] then mf["ws-title"] = args['title']

-- append section if there is one if args["section"] then mf["ws-title"] = mf["ws-title"] .. " — " .. args["section"] end end local author = get_arg_or_override(args, "contributor") if not author then author = get_arg_or_override(args, "section_author") end if not author then author = get_arg_or_override(args, "author") end if author then mf['ws-author'] = author end local translator = get_arg_or_override(args, "translator") if translator then mf['ws-translator'] = translator end local year = get_arg_or_override(args, "year") if year then mf['ws-year'] = year end if args['cover'] then mf['ws-cover'] = args['cover'] end return mf end

--[=[ Construct the Help:Microformat for the page.

This is in the form: Title here...  ... ]=] function p.microformat(frame) local args = getArgs(frame)

local mf_div = construct_mf_wrapper(args) local mf = collect_mf_data(args)

append_mf_values(mf_div, mf) return tostring(mf_div) end

function make_category_list(categories) local s = "" for k,v in pairs(categories) do s = s .. "\n" end return s end

--[=[ Detect explicit formatting in fields like "section" and "title" ]=] function explicit_formatting(str) return string.match(str, "'''?") or string.match(str, "<%s*/?%s*[iIbB]%s*>") -- add more cases here end

function check_non_existent_author_pages(args, param, categories)

if args[param] then -- some pages expect an invalid author local special = false local lower_arg = string.lower(args[param]) if lower_arg == "unknown" or lower_arg == "not mentioned" then special = true end if not special then local target = mw.title.makeTitle("Author", args[param]) -- expensive function! if not target or not target.exists then table.insert(categories, "Works with non-existent author pages") end end end end

--[=[ Construct the automatic categories for the header ]=] function p.categories(frame) local args = getArgs(frame) local categories = {} local this_page = mw.title.getCurrentTitle;

if args["override_author"] then table.insert(categories, "Pages with override author") end if this_page:inNamespaces(0, 114) then check_non_existent_author_pages(args, "author", categories) check_non_existent_author_pages(args, "editor", categories) check_non_existent_author_pages(args, "translator", categories) check_non_existent_author_pages(args, "section_translator", categories) check_non_existent_author_pages(args, "section_author", categories) check_non_existent_author_pages(args, "contributor", categories) end if args["contributor"] or args["section_author"] then table.insert(categories, "Pages with contributor") end if args["override_contributor"] or args["override_section_author"] then table.insert(categories, "Pages with override contributor") end local author = get_arg_or_override(args, "author") if author and (string.lower(author) == "unknown") then table.insert(categories, "Anonymous texts") end local editor = get_arg_or_override(args, "editor") if editor then editor = string.lower(editor) if editor == "unknown" or editor == "?" then table.insert(categories, "Works with unknown editors") elseif editor == "not mentioned" then table.insert(categories, "Works with unmentioned editors") end end local translator = get_arg_or_override(args, "translator") if translator then translator = string.lower(translator) if translator == "unknown" or translator == "not mentioned" or translator == "?" then table.insert(categories, "Translations without translator information specified") elseif translator == "wikisource" and (this_page.baseText == this_page.text) then -- if a basepage -- ?? why is this not done by ?? table.insert(categories, "Wikisource translations") end end

if args["shortcut"] then table.insert(categories, "Mainspace pages with shortcuts") end if args["override_year"] then table.insert(categories, "pages with override year") end if args["noyear"] then table.insert(categories, "pages with noyear") end if args["noyearcat"] then table.insert(categories, "pages with noyearcat") end if args["cover"] then table.insert(categories, "Pages with an export cover") end -- sanity/maintenance checks on various parameters -- allow_explicit_formatting parameter suppresses this check -- used by, for example, Template:Versions if args["allow_explicit_formatting"] == nil and args["allow_illegal_formatting"] == nil then

if args["title"] and explicit_formatting(args['title']) then table.insert(categories, "pages with explicit formatting in header fields") end if args["section"] and explicit_formatting(args['section']) then table.insert(categories, "pages with explicit formatting in header fields") end end

return make_category_list(categories) end

--[=[ Generate a magic word according to the defaultsort parameter ]=] function p.defaultsort(frame) local args = getArgs(frame) local defsortKey = '' if args.defaultsort then defsortKey = args.defaultsort else -- at this point, could construct defaultsort automatically -- by stripping A/An/The as needed end -- if a suitable key is found or constructed, apply it	if defsortKey ~= '' then return frame:preprocess{text = ""} end -- otherwise, don't do anything and use the default return '' end

function get_plain_sister(frame, args, sister_args) local ps_args = {} for k,v in pairs(sister_args) do		if args[v] then ps_args[v] = args[v] end end return frame:expandTemplate{title = "plain sister", args = ps_args} end

--[=[ Return the title span

> --]=] function construct_title(args) local title = mw.html.create("span") :attr("id", "header_title_text") :css({			["font-weight"] = "bold",		}) if args["title"] then title:wikitext(args["title"]) else title:wikitext("Untitled") end return title end

--[=[ Construct the title field ]=] function p.title(frame) local args = getArgs(frame)

local title = construct_title(args) return tostring(title) end

--[=[ Construct the year span --]=] function construct_year(frame, args)

local year = mw.html.create("span") :attr("id", "header_year_text") if args["override_year"] then year:wikitext( '(' .. args["override_year"] .. ')' )	else local year_args = { [1] = args["year"], noprint = "0", nocat = "0", }		if args["noyear"] then year_args['noprint'] = "1" end if args["disambiguation"] and yesno(args['disambiguation']) then -- disambiguations never categorise year_args['nocat'] = "1" else if args["noyearcat"] and yesno(args['noyearcat']) then -- manually no-catted year_args['nocat'] = "1" elseif mw.title.getCurrentTitle.isSubpage then -- only categorise if this is a base page year_args['nocat'] = "1" end end mw.logObject(year_args) year:wikitext(mw.text.trim(frame:expandTemplate{ title = "header/year", args = year_args }))	end return year end

--[=[ Construct the year field ]=]	function p.year(frame) local args = getArgs(frame)

ret = "" if get_arg_or_override(args, "year") then ret = tostring(construct_year(frame, args)) end

return ret end

function create_vcard(id, content, wrap_fn) local span = mw.html.create("span") :addClass("vcard") :css({			['font-style'] = 'italic'		}) :attr("id", id) if wrap_fn then span:tag("span") :addClass("fn") :wikitext(content) else span:wikitext(content) end return span end

function p.author(frame) local args = getArgs(frame) local param_name = "author" local prefix = "by" local id = "header_author_text"

local s = "" local atext; local wrap_fn = true

if args["override_" .. param_name] then s = s .. " "		atext = args["override_" .. param_name] elseif args[param_name] then if args['section'] then s = s .. "&#32;"		else s = s .. " "		end if string.lower(args[param_name]) == "unknown" then atext = "Unknown" wrap_fn = false else atext = "" .. args[param_name] .. "" end s = s .. "''" .. prefix .. "''" .. " "	end local a_span = create_vcard(id, atext, wrap_fn) return s .. tostring(a_span) end

function p.editor(frame) local args = getArgs(frame)

local ed = get_arg_or_override(args, "editor")

-- no editors if ed == nil then return "" end local have_authors = get_arg_or_override(args, "author") ~= nil

local s = " " if have_authors then s = ", " end if not have_authors and not args["section"] then s = s .. " "	end -- need to tidy this up and check for override_editor = unknown|not mentioned|? local special if ed == "?" or string.lower(ed) == "unknown" then special = "editor unknown" elseif string.lower(ed) == "not mentioned" then special = "editor not mentioned" elseif ed ~= nil then s = s .. "edited by" end s = "''" .. s .. "'' "

local etext local wrap_fn = true if args["override_editor"] then etext = args["override_editor"] elseif args["editor"] then

if special then etext = special wrap_fn = false else etext = "" .. args["editor"] .. "" end end local span = create_vcard("header_editor_text", etext, true) return s .. tostring(span) end

function p.translator(frame) local args = getArgs(frame)

local tr = get_arg_or_override(args, "translator")

-- no translator if tr == nil then return "" end

local have_authors = get_arg_or_override(args, "author") ~= nil local have_editors = get_arg_or_override(args, "editor") ~= nil

local s = " " if have_authors or have_editors then s = ", " end if not have_authors and not have_authors and args["section"] == nil then s = s .. " "	end

local special if tr == "?" or string.lower(tr) == "unknown" then special = "translator unknown" elseif string.lower(tr) == "not mentioned" then special = "translator not mentioned" elseif string.lower(tr) == "wikisource" then special = "translated by Wikisource " elseif tr ~= nil then s = s .. "translated by" end s = "''" .. s .. "'' "

local etext local wrap_fn = true if args["override_translator"] then etext = args["override_translator"] elseif args["translator"] then

if special then etext = special wrap_fn = false else etext = "" .. args["translator"] .. "" end end local span = create_vcard("header_translator_text", etext, true) return s .. tostring(span) end

function p.section(frame) local args = getArgs(frame) if not args["section"] then return end local s = " " .. args["section"] .. " "

-- there are synonyms for this local trans = get_arg_or_override(args, "section_translator") if trans == nil then trans = get_arg_or_override(args, "contributing_translator") end

-- there are synonyms for this local sec_author = get_arg_or_override(args, "section_author") if sec_author == nil then sec_author = get_arg_or_override(args, "contributor") end -- first part of section_translator, adds a line return to split to two lines due to length if section translator exists if trans and sec_author then s = s .. " "	end if sec_author then s = s .. " by " s = s .. "" if args["override_section_author"] then s = s .. args["override_section_author"] elseif args["override_contributor"] then s = s .. args["override_contributor"] else s = s .. "" .. sec_author .. "" end s = s .. " " end if trans then if sec_author then s = s .. ","			end s = s .. " translated by " s = s .. "" if args["override_section_translator"] then s = s .. args['override_section_translator'] else s = s .. "" .. trans .. "" end s = s .. " " end return s end

--[=[ Construct the notes field ]=] function p.notes(frame) local args = getArgs(frame) local notes_args = { style = "border-bottom: 1px solid #A0A0A0; background-color: #FAFAFF;", id = navigationNotes }

local wdid = mw.wikibase.getEntityIdForCurrentPage local sister_args = {"disambiguation", "edition", "portal", "related_author", "wikipedia", "commons", "commonscat", "wikiquote", "wikinews", "wiktionary", "wikibooks", "wikidata", "wikivoyage", "wikiversity", "wikispecies", "meta"} local sisters = "" if wdid ~= nil or has_any_arg(args, sister_args) then notes_args['sister'] = (get_plain_sister(frame, args, sister_args)) end

if args["shortcut"] then notes_args['shortcut'] = args["shortcut"] end if args["notes"] then notes_args['content'] = args['notes'] end

if not notes_args['sister'] and not notes_args['content'] and not notes_args['shortcut'] then return nil end

return frame:expandTemplate{title = "header/notes block", args = notes_args} end

return p