Module:Header
Documentation for this module may be created at Module:Header/doc
--[=[
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:
<div id="ws-data" ...>
<span id="ws-title">Title here...</span>
...
<div>
]=]
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, param, categories)
if args[param] then
-- some pages expect an invalid author
local lower_arg = string.lower(args[param])
local attr_data = headerAttributions.attr_data[param] or headerAttributions.attr_data[string.gsub(param, 'section-', '')]
if not attr_data or not attr_data['special_cases'][lower_arg] 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
]=]
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) or args.testing 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)
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
table.insert(categories, 'Pages with shortcuts')
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
local category_links = {}
for k, v in pairs(categories) do
table.insert(category_links, '[[Category:' .. v .. ']]')
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 '[[Category:' .. 'Headers with numerical arguments' .. ']]'
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 .. '/', '([^/]+)/*', '[[Category:%1]]')
return '[[Category:' .. 'Works using categories parameter' .. ']]' .. 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 '[[Category:' .. 'Subpages' .. ']]'
elseif parent_exists then
return '[[Category:' .. title.nsText .. ' subpages' .. ']]'
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 = '<br id=\"header-title=break\" />' .. 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 = '[[Category:' .. 'Pages using duplicate arguments in template calls' .. ']]'
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 = '[[Category:' .. 'Pages using duplicate arguments in template calls' .. ']]'
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'
args.notes_id = args.notes_id or 'navigationNotes'
-- 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 = '[[Category:' .. 'Headers with DefaultSort equal to page title' .. ']]'
args.diffsortcat = '[[Category:' .. 'Headers applying DefaultSort key' .. ']]'
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.main_id = 'translationheadertemplate'
args.notes_id = 'translation-notes'
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