Module:Header

--[=[ This is a module to implement logic for Template:Header and Template:Translation header

TODO: - centuries are defined as starting on XX01, but WS categorizes them as starting on XX00 -- check whether that's a considered policy choice ]=]

require('strict')

local p = {} --p stands for package

local yesno = require('Module:Yesno') local getArgs = require('Module:Arguments').getArgs local tableTools = require('Module:TableTools') local ISO_639_language_name = require('Module:ISO 639').language_name local parent_links = require('Module:Auto parents')._parent_links

local construct_header = require('Module:Header structure').construct_header local headerAttributions = require('Module:Header/attribution') local construct_defaultsort = require('Module:Header/sort')._construct_defaultsort local construct_year = require('Module:Header/year').construct_year

local current_title = mw.title.getCurrentTitle

--[=[ Wrap stylesheet in noexport div ]=] local function get_noexport_stylesheet(template) return tostring(mw.html.create('div'):addClass('ws-noexport'):wikitext(mw.getCurrentFrame:extensionTag('templatestyles', '', {src = template .. '/styles.css'}))) end

--[=[ Get badge if any ]=] local function badge return require('Module:Edition').badge({args = {category = '1', indicator = '1'}}) end

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

This is in the form: Title here...  ... ]=] local function construct_microformat(args) local mf_div = mw.html.create('div') :addClass('ws-noexport') :attr('id', 'ws-data') :css({speak = 'none'}) -- override to show the microformat if yesno(args['show-microformat']) then mf_div:addClass('ws-data-show') end -- collect the MF values here local mf = {};

mf['ws-article-id'] = current_title.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 = args['override-section-author'] or args['section-author'] or args['override-author'] or args['author'] if author then mf['ws-author'] = author end local translator = args['override-translator'] or args['translator'] if translator then mf['ws-translator'] = translator end local year = args['year'] if year then mf['ws-year'] = year end if args['cover'] then mf['ws-cover'] = args['cover'] end for k, v in pairs(mf) do		mf_div:tag('span'):attr('id', k):wikitext(v) end return tostring(mf_div) end

--[=[ Detect explicit formatting in fields like "section" and "title" ]=] local function explicit_formatting(str) return string.match(str, "'''?") or string.match(str, "<%s*/?%s*[iIbB]%s*>") -- add more cases here or come up with a less silly way to do things end

local function check_non_existent_author_pages(args, categories, checkArgs) -- check for cases that aren't supposed to produce a valid link local param = checkArgs.param local tracking_cat = checkArgs.tracking_cat or 'Works with non-existent author pages' if not param or not args[param] or yesno(args[param .. '-nolink']) then return end local lower_arg = string.lower(args[param]) local attr_data = headerAttributions.attr_data[param] or headerAttributions.attr_data[string.gsub(param, 'section%-', '')] if attr_data and attr_data['special_cases'] and attr_data['special_cases'][lower_arg] then return end -- check if page exists local target = mw.title.makeTitle('Author', args[param]) -- expensive function! if not target or not target.exists then table.insert(categories, tracking_cat) end return end

--[=[ Construct the automatic categories for the header ]=] local function construct_categories(args) local categories = {} if args['override-author'] then table.insert(categories, "Pages with override author") end if current_title:inNamespaces(0, 114) or args.testing then local params_to_check = { {param = 'author'}, {param = 'editor'}, {param = 'translator'}, {param = 'composer', tracking_cat = 'Works with non-existent composer pages'}, {param = 'illustrator', tracking_cat = 'Works with non-existent illustrator pages'} }		for k, v in pairs(params_to_check) do			check_non_existent_author_pages(args, categories, v) check_non_existent_author_pages(args, categories, {param = 'section-' .. v.param, tracking_cat = v.tracking_cat}) end end if args['section-author'] then table.insert(categories, 'Pages with contributor') end if args['override-section-author'] then table.insert(categories, 'Pages with override contributor') end local author = args['override-author'] or args['author'] if author and (string.lower(author) == 'unknown') then if args.template_name == 'Translation header' then table.insert(categories, 'Translations of anonymous works') else table.insert(categories, "Anonymous texts") end end local editor = args['override-editor'] or 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 = args['override-translator'] or 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') end end if args["shortcut"] then if current_title:inNamespaces(0) then table.insert(categories, 'Mainspace pages with shortcuts') elseif current_title:inNamespaces(114) then table.insert(categories, 'Translation namespace pages with shortcuts') end end if args['noyear'] then table.insert(categories, "Pages with noyear") end if yesno(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 not yesno(args['allow-explicit-formatting']) 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 -- translation header categories if args.template_name == 'Translation header' then if args.language then table.insert(categories, 'Works originally in ' .. (args.language_name or 'an undefined language')) else table.insert(categories, 'Wikisource translations with no original language') end if not args.original then table.insert(categories, 'Wikisource translations with no original source') end if not current_title.isSubpage then table.insert(categories, 'Wikisource translations') end end -- detect inappropriate template use --[=[	if (args['template-name'] ~= 'Translation header' and translator and string.lower(translator) == 'wikisource') or (current_title:inNamespaces(114) and args['template-name'] ~= 'Translation header') then -- tracking category for pages that should be using translation header? end if current_title:inNamespaces(0) and args['template-name'] == 'Translation header' then -- tracking category for translation header in mainspace? end ]=]	local category_links = {} for k, v in pairs(categories) do		table.insert(category_links, '') end return table.concat(category_links) end

--[=[ Check for numerical parameters (which shouldn't be used) ]=] local function check_for_numerical_arguments(args) for k, v in pairs(args) do		if type(k) == 'number' then return '' end end return '' end

--[=[ Add categories from the categories parameter ]=]

local function manual_categories(args) if not args.categories then return '' end -- Replace each string that ends in a slash with a category definition. -- This does include the final one because we're adding a slash to the input string. local categories = mw.ustring.gsub(args.categories .. '/', '([^/]+)/*', '') return '' .. categories end

--[=[ Categorize subpages ]=] local function check_subpages local title = current_title local parent_exists = false while title.isSubpage and not parent_exists do		title = mw.title.new(title.baseText, title.nsText) parent_exists = title.exists end if parent_exists and title:inNamespaces(0) then return '' elseif parent_exists then return '' else return '' end end

--[=[ Assemble the title ]=] local function header_title(args) local title = args.title or '' local titleSpan = tostring(mw.html.create('span'):attr('id', 'header-title-text'):wikitext(title)) local year = construct_year(args) local attr = headerAttributions.construct_attributions(args) local section = headerAttributions.construct_section(args) if attr ~=  and title ~=  then attr = '' .. attr end return table.concat({titleSpan, year, attr, section}) end

--[=[ Template:Header ]=] function p._header(args, argsWithBlanks) argsWithBlanks = argsWithBlanks or args -- aliases local dup_cat = '' local newArgs = {} for k, v in pairs(args) do		local newkey = string.lower(string.gsub(string.gsub(tostring(k), '_', '-'), ' ', '-')) if newkey ~= tostring(k) then if argsWithBlanks[newkey] then dup_cat = '' end if not args[newkey] then newArgs[newkey] = newArgs[newkey] or v			end end end for k, v in pairs(newArgs) do		args[k] = v		argsWithBlanks[k] = v	end newArgs = {} local aliases = { ['section-author'] = 'contributor', ['section-translator'] = 'contributing%-translator' }	for arg, alias in pairs(aliases) do		for k, v in pairs(args) do			local newkey = string.gsub(k, alias, arg) if newkey ~= tostring(k) then if argsWithBlanks[newkey] then dup_cat = '' end if not args[newkey] then newArgs[newkey] = v				end end end end for k, v in pairs(newArgs) do		args[k] = v		argsWithBlanks[k] = v	end args.sortkey = args.defaultsort or args.sortkey -- add aliases to argsWithBlanks for k, v in pairs(args) do		if not argsWithBlanks[k] then argsWithBlanks[k] = v		end end -- default values args.template_name = args.template_name or 'Header' args.testing = yesno(args.testing or current_title.fullText == 'Template:Header/testcases' or current_title.fullText == 'Template:Translation header/testcases') -- default values for title and section (allow override by setting to blank) if not argsWithBlanks['title'] then args['title'] = parent_links({}) argsWithBlanks['title'] = args['title'] end if not argsWithBlanks['section'] and current_title.isSubpage then args['section'] = current_title.subpageText argsWithBlanks['section'] = args['section'] end -- header args args.pre_container = badge args.header_class = 'wst-header ws-header ws-noexport noprint dynlayout-exempt ' .. (args.header_class or '') args.main_class = 'headertemplate'

-- title args.main_title = header_title(args) -- FIXME: just use Wikidata instead of interwiki links? local interwiki = '' if args.template_name == 'Translation header' and args.language then interwiki = tostring(mw.html.create('span'):addClass('interwiki-info'):attr('id', args.language):attr('title', '(original)')) if args.original and (args.language == 'ang' or args.language == 'enm' or args.language == 'sco') then -- cycle to mul.ws and back around to en.ws interwiki = interwiki ..  .. args.language .. ':en:' .. args.original ..  elseif args.original and args.language and args.language_name then -- general interwiki link interwiki = interwiki ..  .. args.language .. ':' .. args.original ..  end end -- defaultsort tracking categories args.equalsortcat = '' args.diffsortcat = '' args.post_notes = table.concat({		construct_microformat(args),		check_subpages,		manual_categories(args),		construct_categories(args),		check_for_numerical_arguments(argsWithBlanks),		construct_defaultsort(args),		dup_cat,		interwiki	}) return get_noexport_stylesheet('Header') .. construct_header(args) end

function p.header(frame) return p._header(		getArgs(frame),		getArgs(frame, {removeBlanks = false})	) end

--[=[ Template:Translation header ]=] function p._translation_header(args, argsWithBlanks) argsWithBlanks = argsWithBlanks or args args.header_class = 'wst-translation-header' args.template_name = 'Translation header' args.notes_class = 'header-notes' if args.language then args.language_name = ISO_639_language_name(args.language) end return get_noexport_stylesheet('Translation header') .. p._header(args, argsWithBlanks) end

function p.translation_header(frame) return p._translation_header(		getArgs(frame),		getArgs(frame, {removeBlanks = false})	) end

return p