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

模块:Documentation

来自电棍ottowiki
OctoberSama留言 | 贡献2025年6月17日 (二) 21:17的版本
--源代码来自维基百科: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