打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的IP地址会在进行任意编辑后公开展示。

模块:Documentation:修订间差异

来自电棍ottowiki
第22行: 第22行:
-- table for testing purposes.
-- table for testing purposes.
----------------------------------------------------------------------------
----------------------------------------------------------------------------
local function message(cfgKey, valArray, expectType)
local function message(cfgKey, valArray, expectType)
--[[
    --[[
-- Gets a message from the cfg table and formats it if appropriate.
    -- 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'.
    local msg = cfg[cfgKey]
-- If the table valArray is present, strings such as $1, $2 etc. in the
    expectType = expectType or 'string'
-- message are substituted with values from the table keys [1], [2] etc.
    if type(msg) ~= expectType then
-- For example, if the message "foo-message" had the value 'Foo $2 bar $1.',
        error('message: type error in message cfg.' .. cfgKey .. ' (' ..
-- message('foo-message', {'baz', 'qux'}) would return "Foo qux bar baz."
              expectType .. ' expected, got ' .. type(msg) .. ')', 2)
--]]
    end
local msg = cfg[cfgKey]
    if not valArray then
expectType = expectType or 'string'
        return msg
if type(msg) ~= expectType then
    end
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)
    local function getMessageVal(match)
match = tonumber(match)
        match = tonumber(match)
return valArray[match] or error('message: no value found for key $' .. match .. ' in message cfg.' .. cfgKey, 4)
        return valArray[match] or error('message: no value found for key $' .. match .. ' in message cfg.' .. cfgKey, 4)
end
    end


msg = ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
    return ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
return msg
end
end


第54行: 第47行:


local function makeWikilink(page, display)
local function makeWikilink(page, display)
if display then
    if display then
return format('[[%s|%s]]', page, display)
        return format('[[%s|%s]]', page, display)
else
    else
return format('[[%s]]', page)
        return format('[[%s]]', page)
end
    end
end
end


第64行: 第57行:


local function makeCategoryLink(cat, sort)
local function makeCategoryLink(cat, sort)
local catns = mw.site.namespaces[14].name
    local catns = mw.site.namespaces[14].name
return makeWikilink(catns .. ':' .. cat, sort)
    return makeWikilink(catns .. ':' .. cat, sort)
end
end


第71行: 第64行:


local function makeUrlLink(url, display)
local function makeUrlLink(url, display)
return format('[%s %s]', url, display)
    return format('[%s %s]', url, display)
end
end


第77行: 第70行:


local function makeToolbar(...)
local function makeToolbar(...)
local ret = {}
    local ret = {}
local lim = select('#', ...)
    local lim = select('#', ...)
if lim < 1 then
    if lim < 1 then
return nil
        return nil
end
    end
for i = 1, lim do
    for i = 1, lim do
ret[#ret + 1] = select(i, ...)
        ret[#ret + 1] = select(i, ...)
end
    end
-- 'documentation-toolbar'
    -- 'documentation-toolbar'
return format(
    return format(
'<span class="%s">(%s)</span>',
        '<span class="%s">(%s)</span>',
message('toolbar-class'),
        message('start-box-link-classes'),
table.concat(ret, ' &#124; ')
        table.concat(ret, ' &#124; ')
)
    )
end
end


p.makeToolbar = makeToolbar
p.makeToolbar = makeToolbar
第98行: 第91行:
-- Argument processing
-- Argument processing
----------------------------------------------------------------------------
----------------------------------------------------------------------------
local function makeInvokeFunc(funcName)
local function makeInvokeFunc(funcName)
return function (frame)
    return function (frame)
local args = getArgs(frame, {
        local args = getArgs(frame, {
valueFunc = function (key, value)
            valueFunc = function (key, value)
if type(value) == 'string' then
                if type(value) == 'string' then
value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
                    value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
if key == 'heading' or value ~= '' then
                    if key == 'heading' or value ~= '' then
return value
                        return value
else
                    else
return nil
                        return nil
end
                    end
else
                else
return value
                    return value
end
                end
end
            end
})
        })
return p[funcName](args)
        return p[funcName](args)
end
    end
end
end


第122行: 第114行:
-- Entry points
-- Entry points
----------------------------------------------------------------------------
----------------------------------------------------------------------------
function p.nonexistent(frame)
function p.nonexistent(frame)
if mw.title.getCurrentTitle().subpageText == 'testcases' then
    -- Preserve existing nonexistent behavior (testcases notice)
return frame:expandTemplate{title = 'module test cases notice'}
    if mw.title.getCurrentTitle().subpageText == 'testcases' then
else
        return frame:expandTemplate{title = 'module test cases notice'}
return p.main(frame)
    else
end
        return p.main(frame)
    end
end
end


第134行: 第126行:


function p._main(args)
function p._main(args)
--[[
    local env = p.getEnvironment(args)
-- This function defines logic flow for the module.
    local root = mw.html.create()
-- @args - table of arguments passed by the user
    root
--]]
        :wikitext(p._getModuleWikitext(args, env))
local env = p.getEnvironment(args)
        :wikitext(p.protectionTemplate(env))
local root = mw.html.create()
        -- Sandbox notice removed by customization.
root
        :tag('div')
:wikitext(p._getModuleWikitext(args, env))
            :addClass(message('main-div-class'))
:wikitext(p.protectionTemplate(env))
            :newline()
:wikitext(p.sandboxNotice(args, env))
            :wikitext(p._startBox(args, env))
:tag('div')
            :wikitext(p._content(args, env))
-- 'documentation-container'
            :tag('div')
:addClass(message('container'))
                :addClass(message('clear'))
:attr('role', 'complementary')
                :done()
:attr('aria-labelledby', args.heading ~= '' and 'documentation-heading' or nil)
            :newline()
:attr('aria-label', args.heading == '' and 'Documentation' or nil)
            :done()
:newline()
        :wikitext(p._endBox(args, env))
:tag('div')
    return mw.getCurrentFrame():extensionTag(
-- 'documentation'
        'templatestyles', '', {src=cfg['templatestyles-scr']}
:addClass(message('main-div-classes'))
    ) .. tostring(root)
: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
end


第175行: 第151行:
-- Environment settings
-- Environment settings
----------------------------------------------------------------------------
----------------------------------------------------------------------------
function p.getEnvironment(args)
    local env, envFuncs = {}, {}
    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.
                    return val
                end
            end
            return nil
        end
    })


function p.getEnvironment(args)
    function envFuncs.title()
--[[
        local title
-- Returns a table with information about the environment, including title
        local titleArg = args.page
-- objects and other namespace- or path-related data.
        if titleArg then
-- @args - table of arguments passed by the user
            title = mw.title.new(titleArg)
--
        else
-- Title objects include:
            title = mw.title.getCurrentTitle()
-- env.title - the page we are making documentation for (usually the current title)
        end
-- env.templateTitle - the template (or module, file, etc.)
        return title
-- env.docTitle - the /doc subpage.
    end
-- env.sandboxTitle - the /sandbox subpage.
 
-- env.testcasesTitle - the /testcases subpage.
    function envFuncs.templateTitle()
--
        local subjectSpace = env.subjectSpace
-- Data includes:
        local title = env.title
-- env.protectionLevels - the protection levels table of the title object.
        local subpage = title.subpageText
-- env.subjectSpace - the number of the title's subject namespace.
        if subpage == message('sandbox-subpage')
-- env.docSpace - the number of the namespace the title puts its documentation in.
          or subpage == message('testcases-subpage')
-- env.docpageBase - the text of the base page of the /doc, /sandbox and /testcases pages, with namespace.
          or (subpage == message('doc-subpage') and mw.title.getCurrentTitle().namespace == env.docSpace)
-- env.compareUrl - URL of the Special:ComparePages page comparing the sandbox with the template.
        then
--
            return mw.title.makeTitle(subjectSpace, title.baseText)
-- All table lookups are passed through pcall so that errors are caught. If an error occurs, the value
        else
-- returned will be nil.
            return mw.title.makeTitle(subjectSpace, title.text)
--]]
        end
    end
local env, envFuncs = {}, {}


-- Set up the metatable. If triggered we call the corresponding function in the envFuncs table. The value
    function envFuncs.docTitle()
-- returned by that function is memoized in the env table so that we don't call any of the functions
        local title = env.title
-- more than once. (Nils won't be memoized.)
        local docname = args[1]
setmetatable(env, {
        local docpage
__index = function (t, key)
        if docname then
local envFunc = envFuncs[key]
            docpage = docname
if envFunc then
        else
local success, val = pcall(envFunc)
            docpage = env.docpageBase .. '/' .. message('doc-subpage')
if success then
        end
env[key] = val -- Memoise the value.
        return mw.title.new(docpage)
return val
    end
end
end
return nil
end
})


function envFuncs.title()
    function envFuncs.sandboxTitle()
-- The title object for the current page, or a test page passed with args.page.
        return mw.title.new(env.docpageBase .. '/' .. message('sandbox-subpage'))
local title
    end
local titleArg = args.page
if titleArg then
title = mw.title.new(titleArg)
else
title = mw.title.getCurrentTitle()
end
return title
end


function envFuncs.templateTitle()
    function envFuncs.testcasesTitle()
--[[
        return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
-- The template (or module, etc.) title object.
    end
-- 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') then
return mw.title.makeTitle(subjectSpace, title.baseText)
else
return mw.title.makeTitle(subjectSpace, title.text)
end
end


function envFuncs.docTitle()
    function envFuncs.protectionLevels()
--[[
        return env.title.protectionLevels
-- Title object of the /doc subpage.
    end
-- 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()
    function envFuncs.subjectSpace()
-- The protection levels table of the title object.
        return mw.site.namespaces[env.title.namespace].subject.id
return env.title.protectionLevels
    end
end


function envFuncs.subjectSpace()
    function envFuncs.docSpace()
-- The subject namespace number.
        local subjectSpace = env.subjectSpace
return mw.site.namespaces[env.title.namespace].subject.id
        if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
end
            return subjectSpace + 1
        else
            return subjectSpace
        end
    end


function envFuncs.docSpace()
    function envFuncs.docpageBase()
-- The documentation namespace number. For most namespaces this is the
        local templateTitle = env.templateTitle
-- same as the subject namespace. However, pages in the Article, File,
        local docSpace = env.docSpace
-- MediaWiki or Category namespaces must have their /doc, /sandbox and
        local docSpaceText = mw.site.namespaces[docSpace].name
-- /testcases pages in talk space.
        return docSpaceText .. ':' .. templateTitle.text
local subjectSpace = env.subjectSpace
    end
if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
return subjectSpace + 1
else
return subjectSpace
end
end


function envFuncs.docpageBase()
    function envFuncs.compareUrl()
-- The base page of the /doc, /sandbox, and /testcases subpages.
        local templateTitle = env.templateTitle
-- For some namespaces this is the talk page, rather than the template page.
        local sandboxTitle = env.sandboxTitle
local templateTitle = env.templateTitle
        if templateTitle.exists and sandboxTitle.exists then
local docSpace = env.docSpace
            local compareUrl = mw.uri.canonicalUrl(
local docSpaceText = mw.site.namespaces[docSpace].name
                'Special:ComparePages',
-- Assemble the link. docSpace is never the main namespace, so we can hardcode the colon.
                { page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText }
return docSpaceText .. ':' .. templateTitle.text
            )
end
            return tostring(compareUrl)
        else
function envFuncs.compareUrl()
            return nil
-- Diff link between the sandbox and the main template using [[Special:ComparePages]].
        end
local templateTitle = env.templateTitle
    end
local sandboxTitle = env.sandboxTitle
if templateTitle.exists and sandboxTitle.exists then
local compareUrl = mw.uri.canonicalUrl(
'Special:ComparePages',
{ page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText}
)
return tostring(compareUrl)
else
return nil
end
end


return env
    return env
end
end


----------------------------------------------------------------------------
----------------------------------------------------------------------------
-- Auxiliary templates
-- Auxiliary templates
----------------------------------------------------------------------------
----------------------------------------------------------------------------
p.getModuleWikitext = makeInvokeFunc('_getModuleWikitext')
p.getModuleWikitext = makeInvokeFunc('_getModuleWikitext')


function p._getModuleWikitext(args, env)
function p._getModuleWikitext(args, env)
local currentTitle = mw.title.getCurrentTitle()
    local currentTitle = mw.title.getCurrentTitle()
if currentTitle.contentModel ~= 'Scribunto' then return end
    if currentTitle.contentModel ~= 'Scribunto' then return end
pcall(require, currentTitle.prefixedText) -- if it fails, we don't care
    pcall(require, currentTitle.prefixedText) -- attempt to load module
local moduleWikitext = package.loaded["Module:Module wikitext"]
    local moduleWikitext = package.loaded["Module:Module wikitext"]
if moduleWikitext then
    if moduleWikitext then
return moduleWikitext.main()
        return moduleWikitext.main()
end
    end
end
end


-- Sandbox notice completely removed.
function p.sandboxNotice(args, env)
function p.sandboxNotice(args, env)
--[=[
    return nil
-- Generates a sandbox notice for display above sandbox pages.
-- @args - a table of arguments passed by the user
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
--
-- Messages:
-- 'sandbox-notice-image' --> '[[File:Sandbox.svg|50px|alt=|link=]]'
-- 'sandbox-notice-blurb' --> 'This is the $1 for $2.'
-- 'sandbox-notice-diff-blurb' --> 'This is the $1 for $2 ($3).'
-- 'sandbox-notice-pagetype-template' --> '[[Wikipedia:Template test cases|template sandbox]] page'
-- 'sandbox-notice-pagetype-module' --> '[[Wikipedia:Template test cases|module sandbox]] page'
-- 'sandbox-notice-pagetype-other' --> 'sandbox page'
-- 'sandbox-notice-compare-link-display' --> 'diff'
-- 'sandbox-notice-testcases-blurb' --> 'See also the companion subpage for $1.'
-- 'sandbox-notice-testcases-link-display' --> 'test cases'
-- 'sandbox-category' --> 'Template sandboxes'
-- 'module-sandbox-category' --> 'Module sandboxes'
-- 'other-sandbox-category' --> 'Sandboxes outside of template or module namespace'
--]=]
local title = env.title
local sandboxTitle = env.sandboxTitle
local templateTitle = env.templateTitle
local subjectSpace = env.subjectSpace
if not (subjectSpace and title and sandboxTitle and templateTitle
and mw.title.equals(title, sandboxTitle)) then
return nil
end
-- Build the table of arguments to pass to {{ombox}}. We need just two fields, "image" and "text".
local omargs = {}
omargs.image = message('sandbox-notice-image')
-- Get the text. We start with the opening blurb, which is something like
-- "This is the template sandbox for [[Template:Foo]] (diff)."
local text = '__EXPECTUNUSEDTEMPLATE__'
local pagetype, sandboxCat
if subjectSpace == 10 then
pagetype = message('sandbox-notice-pagetype-template')
sandboxCat = message('sandbox-category')
elseif subjectSpace == 828 then
pagetype = message('sandbox-notice-pagetype-module')
sandboxCat = message('module-sandbox-category')
else
pagetype = message('sandbox-notice-pagetype-other')
sandboxCat = message('other-sandbox-category')
end
local pagetypee
if subjectSpace == 10 then
pagetypee = message('template-pagetype')
elseif subjectSpace == 828 then
pagetypee = message('module-pagetype')
else
pagetypee = message('default-pagetype') --message 'other-pagetype' 不存在
end
local templateLink = makeWikilink(templateTitle.prefixedText)
local compareUrl = env.compareUrl
if compareUrl then
local compareDisplay = message('sandbox-notice-compare-link-display')
local compareLink = makeUrlLink(compareUrl, compareDisplay)
text = text .. message('sandbox-notice-diff-blurb', {pagetype, templateLink, compareLink})
else
text = text .. message('sandbox-notice-blurb', {pagetype, templateLink})
end
-- Get the test cases page blurb if the page exists. This is something like
-- "See also the companion subpage for [[Template:Foo/testcases|test cases]]."
local testcasesTitle = env.testcasesTitle
if testcasesTitle and testcasesTitle.exists then
if testcasesTitle.contentModel == "Scribunto" then
local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
local testcasesRunLinkDisplay = message('sandbox-notice-testcases-run-link-display')
local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
text = text .. '<br /><small>' .. message('sandbox-notice-testcases-run-blurb', {pagetypee, testcasesLink, testcasesRunLink}) .. '</small>'
else
local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
text = text .. '<br /><small>' .. message('sandbox-notice-testcases-blurb', {pagetypee, testcasesLink}) .. '</small>'
end
end
-- Add the sandbox to the sandbox category.
omargs.text = text .. makeCategoryLink(sandboxCat)
 
-- 'documentation-clear'
return '<div class="' .. message('clear') .. '"></div>'
.. require('Module:Message box').main('ombox', omargs)
end
end


function p.protectionTemplate(env)
function p.protectionTemplate(env)
-- Generates the padlock icon in the top right.
    local protectionLevels = env.protectionLevels
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    if not protectionLevels then
-- Messages:
        return nil
-- 'protection-template' --> 'pp-template'
    end
-- 'protection-template-args' --> {docusage = 'yes'}
    local editProt = protectionLevels.edit and protectionLevels.edit[1]
local protectionLevels = env.protectionLevels
    local moveProt = protectionLevels.move and protectionLevels.move[1]
if not protectionLevels then
    if editProt then
return nil
        return require('Module:Protection banner')._main{
end
            message('protection-reason-edit'), small = true
local editProt = protectionLevels.edit and protectionLevels.edit[1]
        }
local moveProt = protectionLevels.move and protectionLevels.move[1]
    elseif moveProt and moveProt ~= 'autoconfirmed' then
if editProt then
        return require('Module:Protection banner')._main{
-- The page is edit-protected.
            action = 'move', small = true
return require('Module:Protection banner')._main{
        }
message('protection-reason-edit'), small = true
    else
}
        return nil
elseif moveProt and moveProt ~= 'autoconfirmed' then
    end
-- The page is move-protected but not edit-protected. Exclude move
-- protection with the level "autoconfirmed", as this is equivalent to
-- no move protection at all.
return require('Module:Protection banner')._main{
action = 'move', small = true
}
else
return nil
end
end
end


第469行: 第296行:
-- Start box
-- Start box
----------------------------------------------------------------------------
----------------------------------------------------------------------------
p.startBox = makeInvokeFunc('_startBox')
p.startBox = makeInvokeFunc('_startBox')


function p._startBox(args, env)
function p._startBox(args, env)
--[[
    env = env or p.getEnvironment(args)
-- This function generates the start box.
    local links
-- @args - a table of arguments passed by the user
    local content = args.content
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    if not content or args[1] then
--
        local linksData = p.makeStartBoxLinksData(args, env)
-- The actual work is done by p.makeStartBoxLinksData and p.renderStartBoxLinks which make
        if linksData then
-- the [view] [edit] [history] [purge] links, and by p.makeStartBoxData and p.renderStartBox
            links = p.renderStartBoxLinks(linksData)
-- which generate the box HTML.
        end
--]]
    end
env = env or p.getEnvironment(args)
    local data = p.makeStartBoxData(args, env, links)
local links
    if data then
local content = args.content
        return p.renderStartBox(data)
if not content or args[1] then
    else
-- No need to include the links if the documentation is on the template page itself.
        return nil
local linksData = p.makeStartBoxLinksData(args, env)
    end
if linksData then
links = p.renderStartBoxLinks(linksData)
end
end
-- Generate the start box html.
local data = p.makeStartBoxData(args, env, links)
if data then
return p.renderStartBox(data)
else
-- User specified no heading.
return nil
end
end
end


function p.makeStartBoxLinksData(args, env)
function p.makeStartBoxLinksData(args, env)
--[[
    local subjectSpace = env.subjectSpace
-- Does initial processing of data to make the [view] [edit] [history] [purge] links.
    local title = env.title
-- @args - a table of arguments passed by the user
    local docTitle = env.docTitle
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    if not title or not docTitle then
--
        return nil
-- Messages:
    end
-- 'view-link-display' --> 'view'
    if docTitle.isRedirect then
-- 'edit-link-display' --> 'edit'
        docTitle = docTitle.redirectTarget
-- 'history-link-display' --> 'history'
    end
-- 'purge-link-display' --> 'purge'
-- 'module-preload' --> 'Template:Documentation/preload-module-doc'
-- 'docpage-preload' --> 'Template:Documentation/preload'
-- 'create-link-display' --> 'create'
--]]
local subjectSpace = env.subjectSpace
local title = env.title
local docTitle = env.docTitle
if not title or not docTitle then
return nil
end
if docTitle.isRedirect then  
docTitle = docTitle.redirectTarget
end


-- Create link if /doc doesn't exist.
    -- Create link if /doc doesn't exist.
local preload = args.preload
    local preload = args.preload
if not preload then
    if not preload then
if subjectSpace == 828 then -- Module namespace
        if subjectSpace == 828 then -- Module namespace
preload = message('module-preload')
            preload = message('module-preload')
else
        else
preload = message('docpage-preload')
            preload = message('docpage-preload')
end
        end
end
    end
 
return {
    return {
title = title,
        title = title,
docTitle = docTitle,
        docTitle = docTitle,
-- View, display, edit, and purge links if /doc exists.
        viewLinkDisplay = message('view-link-display'),
viewLinkDisplay = message('view-link-display'),
        editLinkDisplay = message('edit-link-display'),
editLinkDisplay = message('edit-link-display'),
        historyLinkDisplay = message('history-link-display'),
historyLinkDisplay = message('history-link-display'),
        purgeLinkDisplay = message('purge-link-display'),
purgeLinkDisplay = message('purge-link-display'),
        preload = preload,
preload = preload,
        createLinkDisplay = message('create-link-display')
createLinkDisplay = message('create-link-display')
    }
}
end
end


function p.renderStartBoxLinks(data)
function p.renderStartBoxLinks(data)
--[[
    local docTitle = data.docTitle
-- Generates the [view][edit][history][purge] or [create][purge] links from the data table.
    local purgeLink = makeWikilink("Special:Purge/" .. data.title.prefixedText, data.purgeLinkDisplay)
-- @data - a table of data generated by p.makeStartBoxLinksData
    if docTitle.exists then
--]]
        local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
local docTitle = data.docTitle
        local editLink = makeWikilink("Special:EditPage/" .. docTitle.prefixedText, data.editLinkDisplay)
-- yes, we do intend to purge the template page on which the documentation appears
        local historyLink = makeWikilink("Special:PageHistory/" .. docTitle.prefixedText, data.historyLinkDisplay)
local purgeLink = makeWikilink("Special:Purge/" .. data.title.prefixedText, data.purgeLinkDisplay)
        return "&#91;" .. viewLink .. "&#93; &#91;" .. editLink .. "&#93; &#91;" .. historyLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
    else
if docTitle.exists then
        local createLink = makeUrlLink(docTitle:canonicalUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
        return "&#91;" .. createLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
local editLink = makeWikilink("Special:EditPage/" .. docTitle.prefixedText, data.editLinkDisplay)
    end
local historyLink = makeWikilink("Special:PageHistory/" .. docTitle.prefixedText, data.historyLinkDisplay)
return "&#91;" .. viewLink .. "&#93; &#91;" .. editLink .. "&#93; &#91;" .. historyLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
else
local createLink = makeUrlLink(docTitle:canonicalUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
return "&#91;" .. createLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
end
return ret
end
end


function p.makeStartBoxData(args, env, links)
function p.makeStartBoxData(args, env, links)
--[=[
    local subjectSpace = env.subjectSpace
-- Does initial processing of data to pass to the start-box render function, p.renderStartBox.
    if not subjectSpace then
-- @args - a table of arguments passed by the user
        subjectSpace = 2
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    end
-- @links - a string containing the [view][edit][history][purge] links - could be nil if there's an error.
    local data = {}
--
 
-- Messages:
    -- Heading
-- 'documentation-icon-wikitext' --> '[[File:Test Template Info-Icon - Version (2).svg|50px|link=|alt=]]'
    local heading = args.heading
-- 'template-namespace-heading' --> 'Template documentation'
    if heading == '' then
-- 'module-namespace-heading' --> 'Module documentation'
        return nil
-- 'file-namespace-heading' --> 'Summary'
    end
-- 'other-namespaces-heading' --> 'Documentation'
    if heading then
-- 'testcases-create-link-display' --> 'create'
        data.heading = heading
--]=]
    elseif subjectSpace == 10 then -- Template namespace
local subjectSpace = env.subjectSpace
        data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
if not subjectSpace then
    elseif subjectSpace == 828 then -- Module namespace
-- Default to an "other namespaces" namespace, so that we get at least some output
        data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
-- if an error occurs.
    elseif subjectSpace == 6 then -- File namespace
subjectSpace = 2
        data.heading = message('file-namespace-heading')
end
    else
local data = {}
        data.heading = message('other-namespaces-heading')
    end
-- Heading
 
local heading = args.heading -- Blank values are not removed.
    -- Heading CSS
if heading == '' then
    local headingStyle = args['heading-style']
-- Don't display the start box if the heading arg is defined but blank.
    if headingStyle then
return nil
        data.headingStyleText = headingStyle
end
    else
if heading then
        data.headingClass = message('heading-div-class')
data.heading = heading
    end
elseif subjectSpace == 10 then -- Template namespace
 
data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
    if links then
elseif subjectSpace == 828 then -- Module namespace
        data.linksClass = message('start-box-linkclasses')
data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
        data.links = links
elseif subjectSpace == 6 then -- File namespace
    end
data.heading = message('file-namespace-heading')
 
else
    return data
data.heading = message('other-namespaces-heading')
end
-- Heading CSS
local headingStyle = args['heading-style']
if headingStyle then
data.headingStyleText = headingStyle
else
-- 'documentation-heading'
data.headingClass = message('main-div-heading-class')
end
-- Data for the [view][edit][history][purge] or [create] links.
if links then
-- 'mw-editsection-like plainlinks'
data.linksClass = message('start-box-link-classes')
data.links = links
end
return data
end
end


function p.renderStartBox(data)
function p.renderStartBox(data)
-- Renders the start box html.
    local sbox = mw.html.create('div')
-- @data - a table of data generated by p.makeStartBoxData.
    sbox
local sbox = mw.html.create('div')
        :addClass(message('header-div-class'))
sbox
        :newline()
-- 'documentation-startbox'
        :tag('span')
:addClass(message('start-box-class'))
            :addClass(data.headingClass)
:newline()
            :attr('id', 'documentation-heading')
:tag('span')
            :cssText(data.headingStyleText)
:addClass(data.headingClass)
            :wikitext(data.heading)
:attr('id', 'documentation-heading')
    local links = data.links
:cssText(data.headingStyleText)
    if links then
:wikitext(data.heading)
        sbox:tag('span')
local links = data.links
            :addClass(data.linksClass)
if links then
            :attr('id', data.linksId)
sbox:tag('span')
            :wikitext(links)
:addClass(data.linksClass)
    end
:attr('id', data.linksId)
    return tostring(sbox)
:wikitext(links)
end
return tostring(sbox)
end
end


第657行: 第426行:
-- Documentation content
-- Documentation content
----------------------------------------------------------------------------
----------------------------------------------------------------------------
p.content = makeInvokeFunc('_content')
p.content = makeInvokeFunc('_content')


function p._content(args, env)
function p._content(args, env)
-- Displays the documentation contents
    env = env or p.getEnvironment(args)
-- @args - a table of arguments passed by the user
    local docTitle = env.docTitle
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    local content = args.content
env = env or p.getEnvironment(args)
    if not content and docTitle and docTitle.exists then
local docTitle = env.docTitle
        content = args._content or mw.getCurrentFrame():expandTemplate{title = docTitle.prefixedText}
local content = args.content
    end
if not content and docTitle and docTitle.exists then
    return '\n' .. (content or '') .. '\n'
content = args._content or mw.getCurrentFrame():expandTemplate{title = docTitle.prefixedText}
end
-- The line breaks below are necessary so that "=== Headings ===" at the start and end
-- of docs are interpreted correctly.
return '\n' .. (content or '') .. '\n'  
end
end


第678行: 第441行:


function p._contentTitle(args, env)
function p._contentTitle(args, env)
env = env or p.getEnvironment(args)
    env = env or p.getEnvironment(args)
local docTitle = env.docTitle
    local docTitle = env.docTitle
if not args.content and docTitle and docTitle.exists then
    if not args.content and docTitle and docTitle.exists then
return docTitle.prefixedText
        return docTitle.prefixedText
else
    else
return ''
        return ''
end
    end
end
end


第690行: 第453行:
-- End box
-- End box
----------------------------------------------------------------------------
----------------------------------------------------------------------------
p.endBox = makeInvokeFunc('_endBox')
p.endBox = makeInvokeFunc('_endBox')


function p._endBox(args, env)
function p._endBox(args, env)
--[=[
    env = env or p.getEnvironment(args)
-- This function generates the end box (also known as the link box).
    local subjectSpace = env.subjectSpace
-- @args - a table of arguments passed by the user
    local docTitle = env.docTitle
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    if not subjectSpace or not docTitle then
--
        return nil
--]=]
    end
-- Get environment data.
env = env or p.getEnvironment(args)
local subjectSpace = env.subjectSpace
local docTitle = env.docTitle
if not subjectSpace or not docTitle then
return nil
end
-- Check whether we should output the end box at all. Add the end
-- box by default if the documentation exists or if we are in the
-- user, module or template namespaces.
local linkBox = args['link box']
if linkBox == 'off'
or not (
docTitle.exists
or subjectSpace == 2
or subjectSpace == 828
or subjectSpace == 10
)
then
return nil
end


-- Assemble the link box.
    local linkBox = args['link box']
local text = ''
    if linkBox == 'off'
if linkBox then
            or not (docTitle.exists or subjectSpace == 2 or subjectSpace == 828 or subjectSpace == 10)
text = text .. linkBox
    then
else
        return nil
text = text .. (p.makeDocPageBlurb(args, env) or '') -- "This documentation is transcluded from [[Foo]]."
    end
if subjectSpace == 2 or subjectSpace == 10 or subjectSpace == 828 then
-- We are in the user, template or module namespaces.
-- Add sandbox and testcases links.
-- "Editors can experiment in this template's sandbox and testcases pages."
text = text .. (p.makeExperimentBlurb(args, env) or '') .. '<br />'
if not args.content and not args[1] then
-- "Please add categories to the /doc subpage."
-- Don't show this message with inline docs or with an explicitly specified doc page,
-- as then it is unclear where to add the categories.
text = text .. (p.makeCategoriesBlurb(args, env) or '')
end
text = text .. ' ' .. (p.makeSubpagesBlurb(args, env) or '') --"Subpages of this template"
end
end
local box = mw.html.create('div')
-- 'documentation-metadata'
box:attr('role', 'note')
:addClass(message('end-box-class'))
-- 'plainlinks'
:addClass(message('end-box-plainlinks'))
:wikitext(text)
:done()


return '\n' .. tostring(box)
    -- Removed transclusion, experiment, category, and subpages prompts.
end
    local text = ''


function p.makeDocPageBlurb(args, env)
    local box = mw.html.create('div')
--[=[
    box:attr('role', 'note')
-- Makes the blurb "This documentation is transcluded from [[Template:Foo]] (edit, history)".
        :addClass(message('footer-div-class'))
-- @args - a table of arguments passed by the user
        :addClass('plainlinks')
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
        :wikitext(text)
--
        :done()
-- Messages:
-- 'edit-link-display' --> 'edit'
-- 'history-link-display' --> 'history'
-- 'transcluded-from-blurb' -->
-- 'The above [[Wikipedia:Template documentation|documentation]]
-- is [[Help:Transclusion|transcluded]] from $1.'
-- 'module-preload' --> 'Template:Documentation/preload-module-doc'
-- 'create-link-display' --> 'create'
-- 'create-module-doc-blurb' -->
-- 'You might want to $1 a documentation page for this [[Wikipedia:Lua|Scribunto module]].'
--]=]
local docTitle = env.docTitle
if not docTitle then
return nil
end
if docTitle.exists then
-- /doc exists; link to it.
local docLink = makeWikilink(docTitle.prefixedText)
local editDisplay = message('edit-link-display')
local editLink = makeWikilink("Special:EditPage/" .. docTitle.prefixedText, editDisplay)
local historyDisplay = message('history-link-display')
local historyLink = makeWikilink("Special:PageHistory/" .. docTitle.prefixedText, historyDisplay)
return message('transcluded-from-blurb', {docLink})
.. ' '
.. makeToolbar(editLink, historyLink)
.. '<br />'
elseif env.subjectSpace == 828 then
-- /doc does not exist; ask to create it.
local createUrl = docTitle:canonicalUrl{action = 'edit', preload = message('module-preload')}
local createDisplay = message('create-link-display')
local createLink = makeUrlLink(createUrl, createDisplay)
return message('create-module-doc-blurb', {createLink})
.. '<br />'
end
end


function p.makeExperimentBlurb(args, env)
    return '\n' .. tostring(box)
--[[
-- Renders the text "Editors can experiment in this template's sandbox (edit | diff) and testcases (edit) pages."
-- @args - a table of arguments passed by the user
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
--
-- Messages:
-- 'sandbox-link-display' --> 'sandbox'
-- 'sandbox-edit-link-display' --> 'edit'
-- 'compare-link-display' --> 'diff'
-- 'module-sandbox-preload' --> 'Template:Documentation/preload-module-sandbox'
-- 'template-sandbox-preload' --> 'Template:Documentation/preload-sandbox'
-- 'sandbox-create-link-display' --> 'create'
-- 'mirror-edit-summary' --> 'Create sandbox version of $1'
-- 'mirror-link-display' --> 'mirror'
-- 'mirror-link-preload' --> 'Template:Documentation/mirror'
-- 'sandbox-link-display' --> 'sandbox'
-- 'testcases-link-display' --> 'testcases'
-- 'testcases-edit-link-display'--> 'edit'
-- 'template-sandbox-preload' --> 'Template:Documentation/preload-sandbox'
-- 'testcases-create-link-display' --> 'create'
-- 'testcases-link-display' --> 'testcases'
-- 'testcases-edit-link-display' --> 'edit'
-- 'module-testcases-preload' --> 'Template:Documentation/preload-module-testcases'
-- 'template-testcases-preload' --> 'Template:Documentation/preload-testcases'
-- 'experiment-blurb-module' --> 'Editors can experiment in this module's $1 and $2 pages.'
-- 'experiment-blurb-template' --> 'Editors can experiment in this template's $1 and $2 pages.'
--]]
local subjectSpace = env.subjectSpace
local templateTitle = env.templateTitle
local sandboxTitle = env.sandboxTitle
local testcasesTitle = env.testcasesTitle
local templatePage = templateTitle.prefixedText
if not subjectSpace or not templateTitle or not sandboxTitle or not testcasesTitle then
return nil
end
-- Make links.
local sandboxLinks, testcasesLinks
if sandboxTitle.exists then
local sandboxPage = sandboxTitle.prefixedText
local sandboxDisplay = message('sandbox-link-display')
local sandboxLink = makeWikilink(sandboxPage, sandboxDisplay)
local sandboxEditDisplay = message('sandbox-edit-link-display')
local sandboxEditLink = makeWikilink("Special:EditPage/" .. sandboxPage, sandboxEditDisplay)
local compareUrl = env.compareUrl
local compareLink
if compareUrl then
local compareDisplay = message('compare-link-display')
compareLink = makeUrlLink(compareUrl, compareDisplay)
end
sandboxLinks = sandboxLink .. ' ' .. makeToolbar(sandboxEditLink, compareLink)
else
local sandboxPreload
if subjectSpace == 828 then
sandboxPreload = message('module-sandbox-preload')
else
sandboxPreload = message('template-sandbox-preload')
end
local sandboxCreateUrl = sandboxTitle:canonicalUrl{action = 'edit', preload = sandboxPreload}
local sandboxCreateDisplay = message('sandbox-create-link-display')
local sandboxCreateLink = makeUrlLink(sandboxCreateUrl, sandboxCreateDisplay)
local mirrorSummary = message('mirror-edit-summary', {makeWikilink(templatePage)})
local mirrorPreload = message('mirror-link-preload')
local mirrorUrl = sandboxTitle:canonicalUrl{action = 'edit', preload = mirrorPreload, summary = mirrorSummary}
if subjectSpace == 828 then
mirrorUrl = sandboxTitle:canonicalUrl{action = 'edit', preload = templateTitle.prefixedText, summary = mirrorSummary}
end
local mirrorDisplay = message('mirror-link-display')
local mirrorLink = makeUrlLink(mirrorUrl, mirrorDisplay)
sandboxLinks = message('sandbox-link-display') .. ' ' .. makeToolbar(sandboxCreateLink, mirrorLink)
end
if testcasesTitle.exists then
local testcasesPage = testcasesTitle.prefixedText
local testcasesDisplay = message('testcases-link-display')
local testcasesLink = makeWikilink(testcasesPage, testcasesDisplay)
local testcasesEditUrl = testcasesTitle:canonicalUrl{action = 'edit'}
local testcasesEditDisplay = message('testcases-edit-link-display')
local testcasesEditLink = makeWikilink("Special:EditPage/" .. testcasesPage, testcasesEditDisplay)
-- for Modules, add testcases run link if exists
if testcasesTitle.contentModel == "Scribunto"  and testcasesTitle.talkPageTitle and testcasesTitle.talkPageTitle.exists then
local testcasesRunLinkDisplay = message('testcases-run-link-display')
local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink, testcasesRunLink)
else
testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink)
end
else
local testcasesPreload
if subjectSpace == 828 then
testcasesPreload = message('module-testcases-preload')
else
testcasesPreload = message('template-testcases-preload')
end
local testcasesCreateUrl = testcasesTitle:canonicalUrl{action = 'edit', preload = testcasesPreload}
local testcasesCreateDisplay = message('testcases-create-link-display')
local testcasesCreateLink = makeUrlLink(testcasesCreateUrl, testcasesCreateDisplay)
testcasesLinks = message('testcases-link-display') .. ' ' .. makeToolbar(testcasesCreateLink)
end
local messageName
if subjectSpace == 828 then
messageName = 'experiment-blurb-module'
else
messageName = 'experiment-blurb-template'
end
return message(messageName, {sandboxLinks, testcasesLinks})
end
end
function p.makeCategoriesBlurb(args, env)
--[[
-- Generates the text "Please add categories to the /doc subpage."
-- @args - a table of arguments passed by the user
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
-- Messages:
-- 'doc-link-display' --> '/doc'
-- 'add-categories-blurb' --> 'Please add categories to the $1 subpage.'
--]]
local docTitle = env.docTitle
if not docTitle then
return nil
end
local docPathLink = makeWikilink(docTitle.prefixedText, message('doc-link-display'))
return message('add-categories-blurb', {docPathLink})
end
function p.makeSubpagesBlurb(args, env)
--[[
-- Generates the "Subpages of this template" link.
-- @args - a table of arguments passed by the user
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
-- Messages:
-- 'template-pagetype' --> 'template'
-- 'module-pagetype' --> 'module'
-- 'default-pagetype' --> 'page'
-- 'subpages-link-display' --> 'Subpages of this $1'
--]]
local subjectSpace = env.subjectSpace
local templateTitle = env.templateTitle
if not subjectSpace or not templateTitle then
return nil
end
local pagetype
if subjectSpace == 10 then
pagetype = message('template-pagetype')
elseif subjectSpace == 828 then
pagetype = message('module-pagetype')
else
pagetype = message('default-pagetype')
end
local subpagesLink = makeWikilink(
'Special:PrefixIndex/' .. templateTitle.prefixedText .. '/',
message('subpages-link-display', {pagetype})
)
return message('subpages-blurb', {subpagesLink})
end
----------------------------------------------------------------------------
-- Tracking categories
----------------------------------------------------------------------------


function p.addTrackingCategories(env)
function p.addTrackingCategories(env)
--[[
    local title = env.title
-- Check if {{documentation}} is transcluded on a /doc or /testcases page.
    local subjectSpace = env.subjectSpace
-- @env - environment table containing title objects, etc., generated with p.getEnvironment
    if not title or not subjectSpace then
        return nil
-- Messages:
    end
-- 'display-strange-usage-category' --> true
    local subpage = title.subpageText
-- 'doc-subpage' --> 'doc'
    if message('display-strange-usage-category', nil, 'boolean')
-- 'testcases-subpage' --> 'testcases'
            and (
-- 'strange-usage-category' --> 'Wikipedia pages with strange ((documentation)) usage'
                    subpage == message('doc-subpage')
--
                    or (subjectSpace ~= 828 and subpage == message('testcases-subpage'))
-- /testcases pages in the module namespace are not categorised, as they may have
            )
-- {{documentation}} transcluded automatically.
    then
--]]
        return makeCategoryLink(message('strange-usage-category'))
local title = env.title
    end
local subjectSpace = env.subjectSpace
    return ''
if not title or not subjectSpace then
return nil
end
local subpage = title.subpageText
if message('display-strange-usage-category', nil, 'boolean')
and (
subpage == message('doc-subpage')
or subjectSpace ~= 828 and subpage == message('testcases-subpage')
)
then
return makeCategoryLink(message('strange-usage-category'))
end
return ''
end
end


return p
return p

2025年6月17日 (二) 22:47的版本

第135行Lua错误:message: type error in message cfg.main-div-class (string expected, got nil)

--源代码来自维基百科:https://zh.wikipedia.org/w/index.php?title=Module:Documentation&oldid=87749641
--该部分代码使用CC BY-SA 4.0许可证 (https://creativecommons.org/licenses/by-sa/4.0/)

-- This module implements {{documentation}}.

-- 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.
    --]]
    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|%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 class="%s">(%s)</span>',
        message('start-box-link-classes'),
        table.concat(ret, ' &#124; ')
    )
end

p.makeToolbar = makeToolbar

----------------------------------------------------------------------------
-- Argument processing
----------------------------------------------------------------------------
local function makeInvokeFunc(funcName)
    return function (frame)
        local args = getArgs(frame, {
            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(frame)
    -- Preserve existing nonexistent behavior (testcases notice)
    if mw.title.getCurrentTitle().subpageText == 'testcases' then
        return frame:expandTemplate{title = 'module test cases notice'}
    else
        return p.main(frame)
    end
end

p.main = makeInvokeFunc('_main')

function p._main(args)
    local env = p.getEnvironment(args)
    local root = mw.html.create()
    root
        :wikitext(p._getModuleWikitext(args, env))
        :wikitext(p.protectionTemplate(env))
        -- Sandbox notice removed by customization.
        :tag('div')
            :addClass(message('main-div-class'))
            :newline()
            :wikitext(p._startBox(args, env))
            :wikitext(p._content(args, env))
            :tag('div')
                :addClass(message('clear'))
                :done()
            :newline()
            :done()
        :wikitext(p._endBox(args, env))
    return mw.getCurrentFrame():extensionTag(
        'templatestyles', '', {src=cfg['templatestyles-scr']}
    ) .. tostring(root)
end

----------------------------------------------------------------------------
-- Environment settings
----------------------------------------------------------------------------
function p.getEnvironment(args)
    local env, envFuncs = {}, {}
    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.
                    return val
                end
            end
            return nil
        end
    })

    function envFuncs.title()
        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()
        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()
        local title = env.title
        local docname = args[1]
        local docpage
        if docname then
            docpage = docname
        else
            docpage = env.docpageBase .. '/' .. message('doc-subpage')
        end
        return mw.title.new(docpage)
    end

    function envFuncs.sandboxTitle()
        return mw.title.new(env.docpageBase .. '/' .. message('sandbox-subpage'))
    end

    function envFuncs.testcasesTitle()
        return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
    end

    function envFuncs.protectionLevels()
        return env.title.protectionLevels
    end

    function envFuncs.subjectSpace()
        return mw.site.namespaces[env.title.namespace].subject.id
    end

    function envFuncs.docSpace()
        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()
        local templateTitle = env.templateTitle
        local docSpace = env.docSpace
        local docSpaceText = mw.site.namespaces[docSpace].name
        return docSpaceText .. ':' .. templateTitle.text
    end

    function envFuncs.compareUrl()
        local templateTitle = env.templateTitle
        local sandboxTitle = env.sandboxTitle
        if templateTitle.exists and sandboxTitle.exists then
            local compareUrl = mw.uri.canonicalUrl(
                'Special:ComparePages',
                { page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText }
            )
            return tostring(compareUrl)
        else
            return nil
        end
    end

    return env
end

----------------------------------------------------------------------------
-- Auxiliary templates
----------------------------------------------------------------------------
p.getModuleWikitext = makeInvokeFunc('_getModuleWikitext')

function p._getModuleWikitext(args, env)
    local currentTitle = mw.title.getCurrentTitle()
    if currentTitle.contentModel ~= 'Scribunto' then return end
    pcall(require, currentTitle.prefixedText) -- attempt to load module
    local moduleWikitext = package.loaded["Module:Module wikitext"]
    if moduleWikitext then
        return moduleWikitext.main()
    end
end

-- Sandbox notice completely removed.
function p.sandboxNotice(args, env)
    return nil
end

function p.protectionTemplate(env)
    local protectionLevels = env.protectionLevels
    if not protectionLevels then
        return nil
    end
    local editProt = protectionLevels.edit and protectionLevels.edit[1]
    local moveProt = protectionLevels.move and protectionLevels.move[1]
    if editProt then
        return require('Module:Protection banner')._main{
            message('protection-reason-edit'), small = true
        }
    elseif moveProt and moveProt ~= 'autoconfirmed' then
        return require('Module:Protection banner')._main{
            action = 'move', small = true
        }
    else
        return nil
    end
end

----------------------------------------------------------------------------
-- Start box
----------------------------------------------------------------------------
p.startBox = makeInvokeFunc('_startBox')

function p._startBox(args, env)
    env = env or p.getEnvironment(args)
    local links
    local content = args.content
    if not content or args[1] then
        local linksData = p.makeStartBoxLinksData(args, env)
        if linksData then
            links = p.renderStartBoxLinks(linksData)
        end
    end
    local data = p.makeStartBoxData(args, env, links)
    if data then
        return p.renderStartBox(data)
    else
        return nil
    end
end

function p.makeStartBoxLinksData(args, env)
    local subjectSpace = env.subjectSpace
    local title = env.title
    local docTitle = env.docTitle
    if not title or not docTitle then
        return nil
    end
    if docTitle.isRedirect then
        docTitle = docTitle.redirectTarget
    end

    -- Create link if /doc doesn't exist.
    local preload = args.preload
    if not preload then
        if subjectSpace == 828 then -- Module namespace
            preload = message('module-preload')
        else
            preload = message('docpage-preload')
        end
    end

    return {
        title = title,
        docTitle = docTitle,
        viewLinkDisplay = message('view-link-display'),
        editLinkDisplay = message('edit-link-display'),
        historyLinkDisplay = message('history-link-display'),
        purgeLinkDisplay = message('purge-link-display'),
        preload = preload,
        createLinkDisplay = message('create-link-display')
    }
end

function p.renderStartBoxLinks(data)
    local docTitle = data.docTitle
    local purgeLink = makeWikilink("Special:Purge/" .. data.title.prefixedText, data.purgeLinkDisplay)
    if docTitle.exists then
        local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
        local editLink = makeWikilink("Special:EditPage/" .. docTitle.prefixedText, data.editLinkDisplay)
        local historyLink = makeWikilink("Special:PageHistory/" .. docTitle.prefixedText, data.historyLinkDisplay)
        return "&#91;" .. viewLink .. "&#93; &#91;" .. editLink .. "&#93; &#91;" .. historyLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
    else
        local createLink = makeUrlLink(docTitle:canonicalUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
        return "&#91;" .. createLink .. "&#93; &#91;" .. purgeLink .. "&#93;"
    end
end

function p.makeStartBoxData(args, env, links)
    local subjectSpace = env.subjectSpace
    if not subjectSpace then
        subjectSpace = 2
    end
    local data = {}

    -- Heading
    local heading = args.heading
    if heading == '' then
        return nil
    end
    if heading then
        data.heading = heading
    elseif subjectSpace == 10 then -- Template namespace
        data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
    elseif subjectSpace == 828 then -- Module namespace
        data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
    elseif subjectSpace == 6 then -- File namespace
        data.heading = message('file-namespace-heading')
    else
        data.heading = message('other-namespaces-heading')
    end

    -- Heading CSS
    local headingStyle = args['heading-style']
    if headingStyle then
        data.headingStyleText = headingStyle
    else
        data.headingClass = message('heading-div-class')
    end

    if links then
        data.linksClass = message('start-box-linkclasses')
        data.links = links
    end

    return data
end

function p.renderStartBox(data)
    local sbox = mw.html.create('div')
    sbox
        :addClass(message('header-div-class'))
        :newline()
        :tag('span')
            :addClass(data.headingClass)
            :attr('id', 'documentation-heading')
            :cssText(data.headingStyleText)
            :wikitext(data.heading)
    local links = data.links
    if links then
        sbox:tag('span')
            :addClass(data.linksClass)
            :attr('id', data.linksId)
            :wikitext(links)
    end
    return tostring(sbox)
end

----------------------------------------------------------------------------
-- Documentation content
----------------------------------------------------------------------------
p.content = makeInvokeFunc('_content')

function p._content(args, env)
    env = env or p.getEnvironment(args)
    local docTitle = env.docTitle
    local content = args.content
    if not content and docTitle and docTitle.exists then
        content = args._content or mw.getCurrentFrame():expandTemplate{title = docTitle.prefixedText}
    end
    return '\n' .. (content or '') .. '\n'
end

p.contentTitle = makeInvokeFunc('_contentTitle')

function p._contentTitle(args, env)
    env = env or p.getEnvironment(args)
    local docTitle = env.docTitle
    if not args.content and docTitle and docTitle.exists then
        return docTitle.prefixedText
    else
        return ''
    end
end

----------------------------------------------------------------------------
-- End box
----------------------------------------------------------------------------
p.endBox = makeInvokeFunc('_endBox')

function p._endBox(args, env)
    env = env or p.getEnvironment(args)
    local subjectSpace = env.subjectSpace
    local docTitle = env.docTitle
    if not subjectSpace or not docTitle then
        return nil
    end

    local linkBox = args['link box']
    if linkBox == 'off'
            or not (docTitle.exists or subjectSpace == 2 or subjectSpace == 828 or subjectSpace == 10)
    then
        return nil
    end

    -- Removed transclusion, experiment, category, and subpages prompts.
    local text = ''

    local box = mw.html.create('div')
    box:attr('role', 'note')
        :addClass(message('footer-div-class'))
        :addClass('plainlinks')
        :wikitext(text)
        :done()

    return '\n' .. tostring(box)
end

function p.addTrackingCategories(env)
    local title = env.title
    local subjectSpace = env.subjectSpace
    if not title or not subjectSpace then
        return nil
    end
    local subpage = title.subpageText
    if message('display-strange-usage-category', nil, 'boolean')
            and (
                    subpage == message('doc-subpage')
                    or (subjectSpace ~= 828 and subpage == message('testcases-subpage'))
            )
    then
        return makeCategoryLink(message('strange-usage-category'))
    end
    return ''
end

return p