--[=[
This is a module to implement logic for [[MediaWiki:Proofreadpage index 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.
Implemented so far:
* Status categorisation and field
* Some auxiliary data fields
]=]
local getArgs = require('Module:Arguments').getArgs
local messageBox = require('Module:Message box')
local ISO_639 = require('Module:ISO 639')
local index_talk_remarks = require('Module:Index talk remarks')._index_talk_remarks
local error_text = require('Module:Error')['error']
local p = {} --p stands for package
local cfg = require('Module:Proofreadpage index template/config/sandbox')
local function process_args(args)
-- set any defaults
for k, v in pairs(cfg.defaults) do
if args[k] == nil then
args[k] = cfg.defaults[k]
end
end
args.pageTitle = (args.pageTitle and mw.title.new(args.pageTitle)) or mw.title.getCurrentTitle()
args.fileTitle = mw.title.makeTitle('File', args.pageTitle.rootText)
args.talkPageTitle = args.pageTitle.talkPageTitle
return args
end
local function construct_cat(cat)
return '[[Category:' .. cat .. ']]'
end
local function construct_cat_link(cat, text)
return '[[:Category:' .. cat .. '|' .. (text or cat) .. ']]'
end
-- construct a basic "field" row
local function construct_field(id, content)
if id == nil or content == nil then
return nil
elseif not cfg.headings[id] then
error(cfg.missing_heading_id(id))
end
local tr = mw.html.create('tr')
:attr('id', 'ws-index-' .. id .. '-row')
:addClass('ws-index-row')
:tag('th')
:attr('scope', 'row')
:attr('id', 'ws-index-' .. id .. '-label')
:addClass('ws-index-label')
:wikitext(cfg.headings[id]['txt'])
:done()
:tag('td')
:attr('id', 'ws-index-' .. id .. '-value')
:addClass('ws-index-value')
:wikitext(content)
:allDone()
return tr
end
local function construct_status_field(args, statusArgs)
local key = statusArgs.key
local lower_key = string.lower(key)
local config_key = statusArgs.config_key or lower_key
local index_status = args[key] or '_missing'
local sd = cfg[config_key][index_status] or cfg[config_key]['_default']
local index_status_message = sd['txt']
if type(index_status_message) == 'function' then
index_status_message = index_status_message(index_status)
end
if sd['error'] then
index_status_message = error_text({['message'] = index_status_message, ['tag'] = 'span'})
else
index_status_message = construct_cat_link(sd['cat'], index_status_message)
end
return {row = construct_field(lower_key, index_status_message), cat = construct_cat(sd['cat'])}
end
--[=[
Create indicator markup based on config
Loads the config module and creates indicator extension tags after pattern
<indicator name="foo">[[File:Foo.svg|20px|link=bar|caption|alt=Alt text.]]</indcator>
]=]
local function construct_indicator(args, iArgs)
if not (iArgs.include or cfg.indicator_defaults.include)(args) then
return nil
end
local indicator_parts = {
iArgs.image or cfg.indicator_defaults.image,
iArgs.width or cfg.indicator_defaults.width
}
local alt = iArgs.alt or cfg.indicator_defaults.alt
table.insert(indicator_parts, alt and 'alt=' .. alt)
local link = iArgs.link or cfg.indicator_defaults.link
if type(link) == 'function' then
link = link(args)
end
table.insert(indicator_parts, link and 'link=' .. link)
local caption = iArgs.caption or cfg.indicator_defaults.caption
if type(caption) == 'function' then
caption = caption(args)
end
table.insert(indicator_parts, caption)
return mw.getCurrentFrame():extensionTag{
['name'] = 'indicator',
['content'] = '[[' .. table.concat(indicator_parts, '|') .. ']]',
['args'] = {
['name'] = iArgs.name or cfg.indicator_defaults.name
}
}
end
local function _metadata(args)
local metadatatable = mw.html.create('table')
:attr('id', 'ws-index-metadata')
local cats = {}
local indicators = {}
metadatatable:node(construct_field('title', (args['Title'] and table.concat({args['Title'], args['Volume']}, ', ')) or args['Volume']))
local simple_args = {{'Author'}, {'Translator'}, {'Editor'}, {'Illustrator'}, {'Year'}, {'Publisher'}, {'Location', 'place'}}
for i, v in ipairs(simple_args) do
metadatatable:node(construct_field(v[2] or string.lower(v[1]), args[v[1]]))
end
local fileTitle = args.fileTitle
local source = args['Source']
-- expensive
if fileTitle.file.exists then
source = '[[:' .. fileTitle.fullText .. '|' .. source .. ']]'
end
metadatatable:node(construct_field('source', source))
-- Progress
local progress_data = construct_status_field(args, {['key'] = 'Progress', ['config_key'] = 'status'})
metadatatable:node(progress_data.row)
table.insert(cats, progress_data.cat)
-- Transclusion status
local transclusion_data = construct_status_field(args, {['key'] = 'Transclusion'})
metadatatable:node(transclusion_data.row)
table.insert(cats, transclusion_data.cat)
local vdate = args['Validation_date']
if vdate then
local vcat = 'Indexes validated in ' .. vdate
metadatatable:node(construct_field('validation_date', construct_cat_link(vcat, vdate)))
table.insert(cats, construct_cat(vcat))
end
local info_args = {'ISBN', 'OCLC', 'LCCN', 'ARK', --[=['National Archives',]=] 'DOI'}
for i, v in ipairs(info_args) do
local val = args[v]
if val then
local lower_key = string.lower(v)
local link_fn = cfg.url_gens[lower_key]
if link_fn then
metadatatable:node(construct_field(lower_key, link_fn(val, val)))
end
end
end
metadatatable:node(construct_field('volumes', args['Volumes']))
-- language categorisations
if args.Language then
local langs = mw.text.split(args.Language, ',%s*', false)
for _, lang in pairs(langs) do
table.insert(cats, construct_cat('Index pages of works originally in ' .. (ISO_639.language_name(lang) or 'an unknown language')))
end
if #langs > 1 then
table.insert(cats, construct_cat('Index pages of works originally in multiple languages'))
end
end
return {['table'] = metadatatable, cats = table.concat(cats), indicators = table.concat(indicators)}
end
--[=[
Get the image to use as the cover image for this index
If the Image parameter contains an integer, it refers to a page in a DjVu/PDF and can be used directly.
Otherwise, it may be a full image specification that we can use directly,
or just an image filename that we can construct an image specification for.
]=]
local function default_cover_image(link)
return '[[' .. cfg.cover.image .. '|' .. cfg.cover.width .. '|link=' .. link .. '|class=ws-cover]]'
end
local function _cover(args)
-- Workaround for pagelist preview that tries to parse this template without any context and with missing parameters via the API.
if args['Image'] == nil then
return nil
end
local image_number = tonumber(args['Image'])
local image_spec
local cats = {}
if image_number == nil and mw.ustring.find(args['Image'], '^%[%[') ~= nil then
-- Image param is not a (page) number and looks like a full image specification
image_spec = args['Image']
-- Add a tracking category
table.insert(cats, construct_cat('Image based indexes'))
elseif image_number == nil then
-- Image param is not a (page) number and is probably a filename with or without File: prefix
image_spec = mw.ustring.gsub(args['Image'], '^[Ff]ile:', '')
image_spec = mw.ustring.gsub(args['Image'], '^[Ii]mage:', '')
image_spec = '[[File:' .. image_spec .. '|' .. cfg.cover.width .. '|class=ws-cover]]'
-- Add a tracking category
table.insert(cats, construct_cat('Image based indexes'))
elseif args.fileTitle.file.exists then
-- It's a DjVu/PDF-backed index, so we fetch the cover image from a page in the (multipage) file.
image_spec = '[[' .. args.fileTitle.prefixedText .. '|' .. cfg.cover.width .. '|page=' .. image_number .. '|class=ws-cover]]'
else
-- Our associated file doesn't exist so use a placeholder
local image_link = args.fileTitle.prefixedText
if mw.ustring.find(args.fileTitle.rootText, '^.*%.%w+') == nil then
image_link = 'Special:Upload'
end
image_spec = default_cover_image(image_link)
-- Add a tracking category
table.insert(cats, construct_cat('Indexes with missing files'))
end
return image_spec .. table.concat(cats)
end
local function _remarks(args)
if args['Remarks'] then
return mw.html.create('td')
:attr('id', 'ws-index-remarks')
:newline()
:wikitext(mw.getCurrentFrame():preprocess(args['Remarks']))
else
return mw.html.create('td')
:attr('id', 'ws-index-remarks-empty')
end
end
local function _main(args)
args = process_args(args)
local talkremarks = ''
if args.talkPageTitle.exists then
talkremarks = index_talk_remarks({
notes = mw.getCurrentFrame():callParserFunction('#lsth', args.talkPageTitle.prefixedText, cfg.quick_notes_header),
index = args.talkPageTitle.text
})
end
local metadata_data = _metadata(args)
local sortkey = mw.getCurrentFrame():callParserFunction('DEFAULTSORT', {args['Key'] or args.pageTitle.text})
local is = {}
for _, v in pairs(cfg.indicators) do
table.insert(is, construct_indicator(args, v))
end
table.insert(is, metadata_data.indicators)
local indicators = table.concat(is)
local outertable = mw.html.create('table')
:attr('id', 'ws-index-container')
local outertable_tr = outertable:tag('tr')
outertable_tr
:tag('td')
:attr('id', 'ws-index-main-cell')
:tag('table')
:attr('id', 'ws-index-main-table')
:tag('tr'):tag('td')
:tag('div')
:attr('id', 'ws-index-cover-container')
:wikitext(_cover(args))
:done()
:node(metadata_data['table'])
:done()
:tag('tr'):tag('td'):tag('div')
:attr('id', 'ws-index-pagelist-container')
:addClass('mw-collapsible')
:tag('em'):wikitext(cfg.pagelist.pages.txt):done()
:wikitext(' ')
:tag('span')
:attr('id', 'ws-index-pagelist-legend')
:wikitext(cfg.pagelist.legend.txt)
:done()
:tag('div')
:attr('id', 'ws-index-pagelist')
:addClass('index-pagelist mw-collapsible-content')
:newline()
:wikitext(args['Pages'] and mw.text.trim(args['Pages']))
:newline()
outertable_tr:node(_remarks(args))
return talkremarks .. indicators .. tostring(outertable) .. metadata_data.cats .. sortkey
end
function p.main(frame)
return _main(getArgs(frame))
end
return p