打开/关闭菜单
打开/关闭外观设置菜单
打开/关闭个人菜单
未登录
未登录用户的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)
    --[[
local msg = cfg[cfgKey]
    -- Gets a message from the cfg table and formats it if appropriate.
expectType = expectType or 'string'
    --]]
if type(msg) ~= expectType then
    local msg = cfg[cfgKey]
error('message: type error in message cfg.' .. cfgKey .. ' (' .. expectType .. ' expected, got ' .. type(msg) .. ')', 2)
    expectType = expectType or 'string'
end
    if type(msg) ~= expectType then
if not valArray then
        error('message: type error in message cfg.' .. cfgKey .. ' (' ..
return msg
              expectType .. ' expected, got ' .. type(msg) .. ')', 2)
end
    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


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


第47行: 第45行:


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


第57行: 第55行:


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


第64行: 第62行:


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


第70行: 第68行:


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


p.makeToolbar = makeToolbar
p.makeToolbar = makeToolbar
第91行: 第84行:
-- 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


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


第126行: 第116行:


function p._main(args)
function p._main(args)
    local env = p.getEnvironment(args)
local env = p.getEnvironment(args)
    local root = mw.html.create()
local root = mw.html.create()
    root
root
        :wikitext(p._getModuleWikitext(args, env))
:wikitext(p._getModuleWikitext(args, env))
        :wikitext(p.protectionTemplate(env))
:wikitext(p.protectionTemplate(env))
        -- Sandbox notice removed by customization.
:wikitext(p.sandboxNotice(args, env))
        :tag('div')
:tag('div')
            :addClass(message('main-div-class'))
:addClass(message('container'))
            :newline()
:attr('role', 'complementary')
            :wikitext(p._startBox(args, env))
:attr('aria-labelledby', args.heading ~= '' and 'documentation-heading' or nil)
            :wikitext(p._content(args, env))
:attr('aria-label', args.heading == '' and 'Documentation' or nil)
            :tag('div')
:newline()
                :addClass(message('clear'))
:tag('div')
                :done()
:addClass(message('main-div-classes'))
            :newline()
:newline()
            :done()
:wikitext(p._startBox(args, env))
        :wikitext(p._endBox(args, env))
:wikitext(p._content(args, env))
    return mw.getCurrentFrame():extensionTag(
:tag('div')
        'templatestyles', '', {src=cfg['templatestyles-scr']}
:addClass(message('clear'))
    ) .. tostring(root)
:done()
:newline()
:done()
:wikitext(p._endBox(args, env))
:done()
:wikitext(p.addTrackingCategories(env))
return mw.getCurrentFrame():extensionTag('templatestyles', '', {src=cfg['templatestyles']}) .. tostring(root)
end
end


第151行: 第147行:
-- Environment settings
-- Environment settings
----------------------------------------------------------------------------
----------------------------------------------------------------------------
function p.getEnvironment(args)
function p.getEnvironment(args)
    local env, envFuncs = {}, {}
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()
setmetatable(env, {
        return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
__index = function (t, key)
    end
local envFunc = envFuncs[key]
if envFunc then
local success, val = pcall(envFunc)
if success then
env[key] = val
return val
end
end
return nil
end
})


    function envFuncs.protectionLevels()
function envFuncs.title()
        return env.title.protectionLevels
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.subjectSpace()
function envFuncs.templateTitle()
        return mw.site.namespaces[env.title.namespace].subject.id
local subjectSpace = env.subjectSpace
    end
local title = env.title
local subpage = title.subpageText
if subpage == message('doc-subpage') then
return mw.title.makeTitle(subjectSpace, title.baseText)
else
return mw.title.makeTitle(subjectSpace, title.text)
end
end


    function envFuncs.docSpace()
function envFuncs.docTitle()
        local subjectSpace = env.subjectSpace
local title = env.title
        if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
local docname = args[1]
            return subjectSpace + 1
local docpage
        else
if docname then
            return subjectSpace
docpage = docname
        end
else
    end
docpage = env.docpageBase .. '/' .. message('doc-subpage')
end
return mw.title.new(docpage)
end
function envFuncs.protectionLevels()
return env.title.protectionLevels
end


    function envFuncs.docpageBase()
function envFuncs.subjectSpace()
        local templateTitle = env.templateTitle
return mw.site.namespaces[env.title.namespace].subject.id
        local docSpace = env.docSpace
end
        local docSpaceText = mw.site.namespaces[docSpace].name
        return docSpaceText .. ':' .. templateTitle.text
    end


    function envFuncs.compareUrl()
function envFuncs.docSpace()
        local templateTitle = env.templateTitle
local subjectSpace = env.subjectSpace
        local sandboxTitle = env.sandboxTitle
if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
        if templateTitle.exists and sandboxTitle.exists then
return subjectSpace + 1
            local compareUrl = mw.uri.canonicalUrl(
else
                'Special:ComparePages',
return subjectSpace
                { page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText }
end
            )
end
            return tostring(compareUrl)
        else
            return nil
        end
    end


    return env
function envFuncs.docpageBase()
end
local templateTitle = env.templateTitle
local docSpace = env.docSpace
local docSpaceText = mw.site.namespaces[docSpace].name
return docSpaceText .. ':' .. templateTitle.text
end
return env
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) -- attempt to load module
pcall(require, currentTitle.prefixedText)
    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
return ''
end
end


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


第296行: 第269行:
-- 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)
env = env or p.getEnvironment(args)
    local links
local links
    local content = args.content
local content = args.content
    if not content or args[1] then
if not content or args[1] then
        local linksData = p.makeStartBoxLinksData(args, env)
local linksData = p.makeStartBoxLinksData(args, env)
        if linksData then
if linksData then
            links = p.renderStartBoxLinks(linksData)
links = p.renderStartBoxLinks(linksData)
        end
end
    end
end
    local data = p.makeStartBoxData(args, env, links)
local data = p.makeStartBoxData(args, env, links)
    if data then
if data then
        return p.renderStartBox(data)
return p.renderStartBox(data)
    else
else
        return nil
return nil
    end
end
end
end


function p.makeStartBoxLinksData(args, env)
function p.makeStartBoxLinksData(args, env)
    local subjectSpace = env.subjectSpace
local subjectSpace = env.subjectSpace
    local title = env.title
local title = env.title
    local docTitle = env.docTitle
local docTitle = env.docTitle
    if not title or not docTitle then
if not title or not docTitle then
        return nil
return nil
    end
end
    if docTitle.isRedirect then
if docTitle.isRedirect then  
        docTitle = docTitle.redirectTarget
docTitle = docTitle.redirectTarget
    end
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 {
local preload = args.preload
        title = title,
if not preload then
        docTitle = docTitle,
if subjectSpace == 828 then
        viewLinkDisplay = message('view-link-display'),
preload = message('module-preload')
        editLinkDisplay = message('edit-link-display'),
else
        historyLinkDisplay = message('history-link-display'),
preload = message('docpage-preload')
        purgeLinkDisplay = message('purge-link-display'),
end
        preload = preload,
end
        createLinkDisplay = message('create-link-display')
    }
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
end


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


function p.makeStartBoxData(args, env, links)
function p.makeStartBoxData(args, env, links)
    local subjectSpace = env.subjectSpace
local subjectSpace = env.subjectSpace
    if not subjectSpace then
if not subjectSpace then
        subjectSpace = 2
subjectSpace = 2
    end
end
    local data = {}
local data = {}
 
    -- Heading
local heading = args.heading
    local heading = args.heading
if heading == '' then
    if heading == '' then
return nil
        return nil
end
    end
if heading then
    if heading then
data.heading = heading
        data.heading = heading
elseif subjectSpace == 10 then
    elseif subjectSpace == 10 then -- Template namespace
data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
        data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
elseif subjectSpace == 828 then
    elseif subjectSpace == 828 then -- Module namespace
data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
        data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
elseif subjectSpace == 6 then
    elseif subjectSpace == 6 then -- File namespace
data.heading = message('file-namespace-heading')
        data.heading = message('file-namespace-heading')
else
    else
data.heading = message('other-namespaces-heading')
        data.heading = message('other-namespaces-heading')
end
    end
 
local headingStyle = args['heading-style']
    -- Heading CSS
if headingStyle then
    local headingStyle = args['heading-style']
data.headingStyleText = headingStyle
    if headingStyle then
else
        data.headingStyleText = headingStyle
data.headingClass = message('main-div-heading-class')
    else
end
        data.headingClass = message('heading-div-class')
    end
if links then
 
data.linksClass = message('start-box-link-classes')
    if links then
data.links = links
        data.linksClass = message('start-box-linkclasses')
end
        data.links = links
    end
return data
 
    return data
end
end


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


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


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


第441行: 第416行:


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


第453行: 第428行:
-- 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)
env = env or p.getEnvironment(args)
    local subjectSpace = env.subjectSpace
local subjectSpace = env.subjectSpace
    local docTitle = env.docTitle
local docTitle = env.docTitle
    if not subjectSpace or not docTitle then
if not subjectSpace or not docTitle or not docTitle.exists then
        return nil
return nil
    end
end
local linkBox = args['link box']
if linkBox == 'off' then
return nil
end


    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 '')
    end
end
local box = mw.html.create('div')
box:attr('role', 'note')
:addClass(message('end-box-class'))
:addClass(message('end-box-plainlinks'))
:wikitext(text)
:done()


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


    local box = mw.html.create('div')
function p.makeDocPageBlurb(args, env)
    box:attr('role', 'note')
local docTitle = env.docTitle
        :addClass(message('footer-div-class'))
if not docTitle or not docTitle.exists then
        :addClass('plainlinks')
return nil
        :wikitext(text)
end
        :done()
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 />'
end


    return '\n' .. tostring(box)
----------------------------------------------------------------------------
end
-- Tracking categories
----------------------------------------------------------------------------


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


return p
return p

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

--源代码来自维基百科: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)
	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

	msg = ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
	return msg
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
	return format('<span class="%s">(%s)</span>', message('toolbar-class'), table.concat(ret, ' | '))
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)
	return p.main(frame)
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))
		:wikitext(p.sandboxNotice(args, env))
		:tag('div')
			: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')
				:addClass(message('main-div-classes'))
				:newline()
				:wikitext(p._startBox(args, env))
				:wikitext(p._content(args, env))
				:tag('div')
					:addClass(message('clear'))
					:done()
				:newline()
				:done()
			:wikitext(p._endBox(args, env))
			:done()
		:wikitext(p.addTrackingCategories(env))
	return mw.getCurrentFrame():extensionTag('templatestyles', '', {src=cfg['templatestyles']}) .. 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
					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('doc-subpage') 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.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
	
	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)
	local moduleWikitext = package.loaded["Module:Module wikitext"]
	if moduleWikitext then
		return moduleWikitext.main()
	end
end

function p.sandboxNotice(args, env)
	return ''
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

	local preload = args.preload
	if not preload then
		if subjectSpace == 828 then
			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 title = data.title
	local links = {}
	
	if docTitle.exists then
		links[#links + 1] = '[' .. makeWikilink(docTitle.prefixedText, data.viewLinkDisplay) .. ']'
		links[#links + 1] = '[' .. makeWikilink('Special:EditPage/' .. docTitle.prefixedText, data.editLinkDisplay) .. ']'
		links[#links + 1] = '[' .. makeWikilink('Special:PageHistory/' .. docTitle.prefixedText, data.historyLinkDisplay) .. ']'
		links[#links + 1] = '[' .. makeWikilink('Special:Purge/' .. title.prefixedText, data.purgeLinkDisplay) .. ']'
		return table.concat(links, ' ')
	else
		links[#links + 1] = '[' .. makeUrlLink(docTitle:canonicalUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay) .. ']'
		links[#links + 1] = '[' .. makeWikilink('Special:Purge/' .. title.prefixedText, data.purgeLinkDisplay) .. ']'
		return table.concat(links, ' ')
	end
end

function p.makeStartBoxData(args, env, links)
	local subjectSpace = env.subjectSpace
	if not subjectSpace then
		subjectSpace = 2
	end
	local data = {}
	
	local heading = args.heading
	if heading == '' then
		return nil
	end
	if heading then
		data.heading = heading
	elseif subjectSpace == 10 then
		data.heading = message('documentation-icon-wikitext') .. ' ' .. message('template-namespace-heading')
	elseif subjectSpace == 828 then
		data.heading = message('documentation-icon-wikitext') .. ' ' .. message('module-namespace-heading')
	elseif subjectSpace == 6 then
		data.heading = message('file-namespace-heading')
	else
		data.heading = message('other-namespaces-heading')
	end
	
	local headingStyle = args['heading-style']
	if headingStyle then
		data.headingStyleText = headingStyle
	else
		data.headingClass = message('main-div-heading-class')
	end
	
	if links then
		data.linksClass = message('start-box-link-classes')
		data.links = links
	end
	
	return data
end

function p.renderStartBox(data)
	local sbox = mw.html.create('div')
	sbox
		:addClass(message('start-box-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)
			: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 or not docTitle.exists then
		return nil
	end
	
	local linkBox = args['link box']
	if linkBox == 'off' then
		return nil
	end

	local text = ''
	if linkBox then
		text = text .. linkBox
	else
		text = text .. (p.makeDocPageBlurb(args, env) or '')
	end
	
	local box = mw.html.create('div')
	box:attr('role', 'note')
		:addClass(message('end-box-class'))
		:addClass(message('end-box-plainlinks'))
		:wikitext(text)
		:done()

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

function p.makeDocPageBlurb(args, env)
	local docTitle = env.docTitle
	if not docTitle or not docTitle.exists then
		return nil
	end
	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 />'
end

----------------------------------------------------------------------------
-- Tracking categories
----------------------------------------------------------------------------

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') then
		return makeCategoryLink(message('strange-usage-category'))
	end
	return ''
end

return p