-- This module implements .  
-- Get required modules.
local getArgs = require('Module:Arguments').getArgs  
-- Get the config table.
local cfg = mw.loadData('Module:Documentation/config')  
local p = {}  
-- Often-used functions.
local ugsub = mw.ustring.gsub
local format = mw.ustring.format  
---
-- Helper functions
---
-- These are defined as local functions, but are made available in the p
-- table for testing purposes.
---  
local function message(cfgKey, valArray, expectType)
--[[
-- Gets a message from the cfg table and formats it if appropriate.
-- The function raises an error if the value from the cfg table is not
-- of the type expectType. The default type for expectType is 'string'.
-- If the table valArray is present, strings such as $1, $2 etc. in the
-- message are substituted with values from the table keys [1], [2] etc.
-- For example, if the message "foo-message" had the value 'Foo $2 bar $1.',
-- message('foo-message', {'baz', 'qux'}) would return "Foo qux bar baz."
--]]
local msg = cfg[cfgKey]
expectType = expectType or 'string'
if type(msg) ~= expectType then
error('message: type error in message cfg.' .. cfgKey .. ' (' .. expectType .. ' expected, got ' .. type(msg) .. ')', 2)
end
if not valArray then
return msg
end  
local function getMessageVal(match)
match = tonumber(match)
return valArray[match] or error('message: no value found for key $' .. match .. ' in message cfg.' .. cfgKey, 4)
end  
return ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
end  
p.message = message  
local function makeWikilink(page, display)
if display then
return format('%s', page, display)
else
return format('%s', page)
end
end  
p.makeWikilink = makeWikilink  
local function makeCategoryLink(cat, sort)
local catns = mw.site.namespaces[14].name
return makeWikilink(catns .. ':' .. cat, sort)
end  
p.makeCategoryLink = makeCategoryLink  
local function makeUrlLink(url, display)
return format('[%s %s]', url, display)
end  
p.makeUrlLink = makeUrlLink  
local function makeToolbar(...)
local ret = {}
local lim = select('#', ...)
if lim < 1 then
return nil
end
for i = 1, lim do
ret[#ret + 1] = select(i, ...)
end
-- 'documentation-toolbar'
return format(
'<span>(%s)</span>',
message('toolbar-class'),
table.concat(ret, ' &#124; ')
end  
p.makeToolbar = makeToolbar  
---
-- Argument processing
---  
local function makeInvokeFunc(funcName)
return function
local args = getArgs(, {
valueFunc = function (key, value)
if type(value) == 'string' then
value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
if key == 'heading' or value ~= '' then
return value
else
return nil
end
else
return value
end
end
})
return p[funcName](args)
end
end  
---
-- Entry points
---  
function p.nonexistent
if mw.title.getCurrentTitle.subpageText == 'testcases' then
return :expandTemplate{title = 'module test cases notice'}
else
return p.main
end
end  
p.main = makeInvokeFunc('_main')  
function p._main(args)
---
-- This function defines logic flow for the module.
-- @args - table of arguments passed by the user
---
local env = p.getEnvironment(args)
local root = mw.html.create
root
:wikitext(p._getModuleWikitext(args, env))
:wikitext(p.protectionTemplate(env))
:wikitext(p.sandboxNotice(args, env))
:tag('div')
-- 'documentation-container'
:addClass(message('container'))
:attr('role', 'complementary')
:attr('aria-labelledby', args.heading ~= '' and 'documentation-heading' or nil)
:attr('aria-label', args.heading == '' and 'Documentation' or nil)
:newline
:tag('div')
-- 'documentation'
:addClass(message('main-div-classes'))
:newline
:wikitext(p._startBox(args, env))
:wikitext(p._content(args, env))
:tag('div')
-- 'documentation-clear'
:addClass(message('clear'))
:done
:newline
:done
:wikitext(p._endBox(args, env))
:done
:wikitext(p.addTrackingCategories(env))
-- 'Module:Documentation/styles.css'
return mw.getCurrentFrame:extensionTag (
'templatestyles', '', {src=cfg['templatestyles']
}) .. tostring(root)
end  
---
-- Environment settings
---  
function p.getEnvironment(args)
---
-- Returns a table with information about the environment, including title
-- objects and other namespace- or path-related data.
-- @args - table of arguments passed by the user
---
-- Title objects include:
-- env.title - the page we are making documentation for (usually the current title)
-- env.templateTitle - the template (or module, file, etc.)
-- env.docTitle - the /doc subpage.
-- env.sandboxTitle - the /sandbox subpage.
-- env.testcasesTitle - the /testcases subpage.
---
-- Data includes:
-- env.protectionLevels - the protection levels table of the title object.
-- env.subjectSpace - the number of the title's subject namespace.
-- env.docSpace - the number of the namespace the title puts its documentation in.
-- env.docpageBase - the text of the base page of the /doc, /sandbox and /testcases pages, with namespace.
-- env.compareUrl - URL of the Special:ComparePages page comparing the sandbox with the template.
---
-- All table lookups are passed through pcall so that errors are caught. If an error occurs, the value
-- returned will be nil.
---  
local env, envFuncs = {}, {}  
-- Set up the metatable. If triggered we call the corresponding function in the envFuncs table. The value
-- returned by that function is memoized in the env table so that we don't call any of the functions
-- more than once. (Nils won't be memoized.)
setmetatable(env, {
__index = function (t, key)
local envFunc = envFuncs[key]
if envFunc then
local success, val = pcall(envFunc)
if success then
env[key] = val -- Memoise the value.
return val
end
end
return nil
end
})  
function envFuncs.title
-- The title object for the current page, or a test page passed with args.page.
local title
local titleArg = args.page
if titleArg then
title = mw.title.new(titleArg)
else
title = mw.title.getCurrentTitle
end
return title
end  
function envFuncs.templateTitle
---
-- The template (or module, etc.) title object.
-- Messages:
-- 'sandbox-subpage' --> 'sandbox'
-- 'testcases-subpage' --> 'testcases'
---
local subjectSpace = env.subjectSpace
local title = env.title
local subpage = title.subpageText
if subpage == message('sandbox-subpage') or subpage == message('testcases-subpage') or (subpage == message('doc-subpage') and mw.title.getCurrentTitle.namespace == env.docSpace) then
return mw.title.makeTitle(subjectSpace, title.baseText)
else
return mw.title.makeTitle(subjectSpace, title.text)
end
end  
function envFuncs.docTitle
---
-- Title object of the /doc subpage.
-- Messages:
-- 'doc-subpage' --> 'doc'
---
local title = env.title
local docname = args[1] -- User-specified doc page.
local docpage
if docname then
docpage = docname
else
docpage = env.docpageBase .. '/' .. message('doc-subpage')
end
return mw.title.new(docpage)
end  
function envFuncs.sandboxTitle
---
-- Title object for the /sandbox subpage.
-- Messages:
-- 'sandbox-subpage' --> 'sandbox'
---
return mw.title.new(env.docpageBase .. '/' .. message('sandbox-subpage'))
end  
function envFuncs.testcasesTitle
---
-- Title object for the /testcases subpage.
-- Messages:
-- 'testcases-subpage' --> 'testcases'
---
return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
end  
function envFuncs.protectionLevels
-- The protection levels table of the title object.
return env.title.protectionLevels
end  
function envFuncs.subjectSpace
-- The subject namespace number.
return mw.site.namespaces[env.title.namespace].subject.id
end  
function envFuncs.docSpace
-- The documentation namespace number. For most namespaces this is the
-- same as the subject namespace. However, pages in the Article, File,
-- MediaWiki or Category namespaces must have their /doc, /sandbox and
-- /testcases pages in talk space.
local subjectSpace = env.subjectSpace
if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
return subjectSpace + 1
else
return subjectSpace
end
end  
function envFuncs.docpageBase
-- The base page of the /doc, /sandbox, and /testcases subpages.