Module:Documentation: Difference between revisions

The Two Worlds Wiki - Documenting Two Worlds since 2008.
Jump to navigation Jump to search
(split out docpage blurb code)
m (219 versions importées)
 
(176 intermediate revisions by 48 users not shown)
Line 1: Line 1:
-- This module implements {{documentation}}.
-- Get required modules.
local getArgs = require('Module:Arguments').getArgs
local htmlBuilder = require('Module:HtmlBuilder')
local messageBox = require('Module:Message box')
-- Get the config table.
local cfg = mw.loadData('Module:Documentation/config')
local p = {}
local p = {}
local defaultDocPage = 'doc'


-- Often-used functions.
local getType = function( namespace, page )
local gsub = mw.ustring.gsub
local pageType = 'template'
 
if namespace == 'Module' then
----------------------------------------------------------------------------
pageType = 'module'
-- Helper functions
elseif namespace == 'Widget' then
--
pageType = 'widget'
-- These are defined as local functions, but are made available in the p
elseif page.fullText:gsub( '/' .. defaultDocPage .. '$', '' ):find( '%.css$' ) then
-- table for testing purposes.
pageType = 'stylesheet'
----------------------------------------------------------------------------
elseif page.fullText:gsub( '/' .. defaultDocPage .. '$', '' ):find( '%.js$' ) then
 
pageType = 'script'
local function message(cfgKey, expectType, valArray)
elseif namespace == 'MediaWiki' then
--[[
pageType = 'message'
-- 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.
-- If the table valArray is present, strings such as $1, $2 etc. in the
-- message are substituted with values from the table keys [1], [2] etc.
-- For example, if the message cfg.fooMessage had the value 'Foo $2 bar $1.',
-- message('fooMessage', 'string', {'baz', 'qux'}) would return "Foo qux bar baz."
--]]
local msg = cfg[cfgKey]
if expectType and type(msg) ~= expectType then
error('message: type error in message cfg.' .. cfgKey .. ' (' .. expectType .. ' expected, got ' .. type(msg) .. ')', 2)
end
end
if not valArray then
return msg
return pageType
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
 
local ret = gsub(msg, '$([1-9][0-9]*)', getMessageVal)
return ret
end
end


p.message = message
-- Creating a documentation page or transclution through {{subst:doc}}
 
function p.create( f )
local function makeWikilink(page, display)
local args = require( 'Module:ProcessArgs' ).norm()
if display then
local page = mw.title.getCurrentTitle()
return mw.ustring.format('[[%s|%s]]', page, display)
local docPage = args.page or page.nsText .. ':' .. page.baseText .. '/' .. defaultDocPage
local out
if not args.content and tostring( page ) == docPage then
out = f:preprocess( '{{subst:Template:Documentation/preload}}' )
else
else
return mw.ustring.format('[[%s]]', page)
local templateArgs = {}
end
for _, key in ipairs{ 'type', 'page', 'content' } do
end
local val = args[key]
 
if val then
p.makeWikilink = makeWikilink
if key == 'content' then val = '\n' .. val .. '\n' end
 
table.insert( templateArgs, key .. '=' .. val )
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 mw.ustring.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 '<small style="font-style: normal;">(' .. table.concat(ret, ' &#124; ') .. ')</small>'
end
 
p.makeToolbar = makeToolbar
 
local function err(msg)
return string.format(
'<strong class="error">[[Module:Documentation]] error: %s</strong>%s',
msg,
makeCategoryLink('Documentation template invocations with errors')
)
end
 
p.err = err
 
----------------------------------------------------------------------------
-- Argument processing
----------------------------------------------------------------------------
 
local function makeInvokeFunc(funcName)
return function (frame)
local headingArg = message('headingArg', 'string')
local args = getArgs(frame, {
valueFunc = function (key, value)
if type(value) == 'string' then
value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
if key == headingArg or value ~= '' then
return value
else
return nil
end
else
return value
end
end
})
return p[funcName](args)
end
end
 
----------------------------------------------------------------------------
-- Main function
----------------------------------------------------------------------------
 
p.main = makeInvokeFunc('_main')
 
function p._main(args)
local env = p.getEnvironment(args)
local root = htmlBuilder.create()
root
.wikitext(p.protectionTemplate(env))
.wikitext(p.sandboxNotice(args, env))
-- This div tag is from {{documentation/start box}}, but moving it here
-- so that we don't have to worry about unclosed tags.
.tag('div')
.attr('id', message('mainDivId', 'string'))
.addClass(message('mainDivClasses', 'string'))
.newline()
.wikitext(p._startBox(args, env))
.wikitext(p._content(args, env))
.tag('div')
.css('clear', 'both') -- So right or left floating items don't stick out of the doc box.
.newline()
.done()
.done()
.wikitext(p._endBox(args, env))
.newline()
.wikitext(p.addTrackingCategories(env))
return tostring(root)
end
 
----------------------------------------------------------------------------
-- Environment settings
----------------------------------------------------------------------------
 
function p.getEnvironment(args)
-- Returns a table with information about the environment, including the title to use, the subject namespace, etc.
-- This is called from p._main using pcall in case we get any errors from exceeding the expensive function count
-- limit, or other perils unknown.
--
-- Data includes:
-- env.title - the title object of the page we are making documentation for (usually the current title)
-- env.subjectSpace - the number of the title's subject namespace.
-- env.docspace - the name of the namespace the title puts its documentation in.
-- env.templatePage - the name of the template page with no namespace or interwiki prefixes.
local env, envFuncs = {}, {}
 
-- Set up the metatable. If a nil value is called, we call that function in the envFuncs table and memoize it
-- in the env table so we don't have to call any of the functions more than once.
setmetatable(env, {
__index = function (t, key)
local envFunc = envFuncs[key]
if envFunc then
local val = envFunc()
env[key] = val
return val
else
return nil
end
end
end
end
})
 
out = '{{documentation|' .. table.concat( templateArgs, '|' ) .. '}}'
function envFuncs.title()
out = out:gsub( '|}}', '}}' )
-- The title object for the current page, or a test page passed with args.page.
local title
if not args.content then
local titleArg = args[message('titleArg', 'string')]
out = out .. '\n<!-- Put categories/interwiki on the documentation page -->'
if titleArg then
title = mw.title.new(titleArg)
if not title then
error(message('titleArgError', 'string', {titleArg}))
end
else
title = mw.title.getCurrentTitle()
end
end
return title
end
function envFuncs.subjectSpace()
-- The subject namespace number.
return mw.site.namespaces[env.title.namespace].subject.id
end
end
function envFuncs.docspace()
if not mw.isSubsting() then
-- The name of the documentation namespace.
out = f:preprocess( out )
local subjectSpace = env.subjectSpace
if not args.nocat then
if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
out = out .. '[[Category:Pages with templates requiring substitution]]'
-- Pages in the Article, File, MediaWiki or Category namespaces must have their
-- /doc, /sandbox and /testcases pages in talk space.
return mw.site.namespaces[subjectSpace].talk.name
else
return env.title.subjectNsText
end
end
end
end
function envFuncs.templatePage()
return out
-- The template page with no namespace or interwiki prefixes.
end
local title = env.title
local subpage = title.subpageText
if subpage == message('sandboxSubpage', 'string') or subpage == message('testcasesSubpage', 'string') then
return title.baseText
else
return title.text
end
end


function envFuncs.docTitle()
-- Header on the documentation page
-- Title object of the /doc subpage.
function p.docPage( f )
local title = env.title
local args = require( 'Module:ProcessArgs' ).merge( true )
local docname = args[1] -- User-specified doc page.
local badDoc = args.baddoc
local docpage
if f:callParserFunction( '#dplvar', '$doc noheader' ) == '1' then
if docname then
if badDoc then
docpage = docname
f:callParserFunction( '#dplvar:set', '$doc bad', '1' )
else
docpage = env.docpageRoot .. '/' .. message('docSubpage', 'string')
end
end
return mw.title.new(docpage)
return
end
end
function envFuncs.docpageRoot()
local page = mw.title.getCurrentTitle()
-- The base page of the /doc, /sandbox, and /testcases subpages.
local namespace = page.nsText
-- For some namespaces this is the talk page, rather than the template page.
local pageType = mw.ustring.lower( args.type or getType( namespace, page ) )
local title = env.title
return (env.docspace or title.nsText) .. ':' .. (env.templatePage or title.text)
end
function envFuncs.sandboxTitle()
local body = mw.html.create( 'div' ):addClass( 'documentation-header' )
-- Title object for the /sandbox subpage.
body
local titleArg = env.docpageRoot .. '/' .. message('sandboxSubpage', 'string')
:css{
local title = mw.title.new(titleArg)
['margin-bottom'] = '0.8em',
if not title then
padding = '0.8em 1em 0.7em',
error(message('titleArgError', 'string', {titleArg}))
['background-color'] = '#' .. ( badDoc and 'F9F2EA' or 'EAF4F9' ),
end
border = '1px solid #AAA'
return title
}
:tag( 'div' )
:css( 'float', 'right' )
:wikitext( '[[', page:fullUrl( 'action=purge' ), ' purge]]' )
:done()
:wikitext(
'This is the documentation page. It ',
pageType == 'module' and 'will' or 'should',
' be transcluded into the main ', pageType, ' page. ',
'See [[Template:Documentation]] for more information'
)
if badDoc then
body:wikitext( "<br>'''This ", pageType, "'s documentation needs improving or additional information.'''" )
end
end
if not ( args.nocat or namespace == 'User' ) then
function envFuncs.testcasesTitle()
body:wikitext( '[[Category:Documentation pages]]' )
-- Title object for the /testcases subpage.
local titleArg = env.docpageRoot .. '/' .. message('testcasesSubpage', 'string')
local title = mw.title.new(titleArg)
if not title then
error(message('titleArgError', 'string', {titleArg}))
end
return title
end
end
function envFuncs.printTitle()
return body
-- Title object for the /Print subpage.
local titleArg = env.templatePage .. '/' .. message('printSubpage', 'string')
local title = mw.title.new(titleArg)
if not title then
error(message('titleArgError', 'string', {titleArg}))
end
return title
end
function env:grab(key)
local success, val = pcall(function() return self[key] end)
return success, val
end
 
return env
end
 
----------------------------------------------------------------------------
-- Auxiliary templates
----------------------------------------------------------------------------
 
function p.sandboxNotice(args, env)
local sandboxNoticeTemplate = message('sandboxNoticeTemplate', 'string')
if not (sandboxNoticeTemplate and env.title.subpageText == message('sandboxSubpage', 'string')) then
return nil
end
local frame = mw.getCurrentFrame()
local notice = htmlBuilder.create()
notice
.tag('div')
.css('clear', 'both')
.done()
.wikitext(frame:expandTemplate{title = sandboxNoticeTemplate, args = {[message('sandboxNoticeLivepageParam')] = args[message('livepageArg', 'string')]}})
return tostring(notice)
end
 
function p.protectionTemplate(env)
local title = env.title
local protectionTemplate = message('protectionTemplate', 'string')
if not (protectionTemplate and title.namespace == 10) then
-- Don't display the protection template if we are not in the template namespace.
return nil
end
local frame = mw.getCurrentFrame()
local function getProtectionLevel(protectionType, page)
-- Gets the protection level for page, or for the current page if page is not specified.
local level = frame:callParserFunction('PROTECTIONLEVEL', protectionType, page)
if level ~= '' then
return level
else
return nil -- The parser function returns the blank string if there is no match.
end
end
local prefixedTitle = title.prefixedText
if getProtectionLevel('move', prefixedTitle) == 'sysop' or getProtectionLevel('edit', prefixedTitle) then
-- The page is full-move protected, or full, template, or semi-protected.
return frame:expandTemplate{title = protectionTemplate, args = message('protectionTemplateArgs', 'table')}
end
return nil
end
 
----------------------------------------------------------------------------
-- Start box
----------------------------------------------------------------------------
 
p.startBox = makeInvokeFunc('_startBox')
 
function p._startBox(args, env)
-- Generate [view][edit][history][purge] or [create] links.
local links
local content = args[message('contentArg', 'string')]
if not content then
-- No need to include the links if the documentation is on the template page itself.
local linksData = p.makeStartBoxLinksData(args, env)
links = p.renderStartBoxLinks(linksData)
end
-- Generate the start box html.
local data = p.makeStartBoxData(args, env, links)
if type(data) == 'table' then
return p.renderStartBox(data)
elseif type(data) == 'string' then
-- data is an error message.
return data
else
-- User specified no heading.
return nil
end
end
end


function p.makeStartBoxLinksData(args, env)
-- Wrapper around the documentation on the main page
local data = {}
function p.page( f )
-- Get title objects.
-- mw.text.trim uses mw.ustring.gsub, which silently fails on large strings
local titleSuccess, title = env:grab('title')
local function trim( s )
if titleSuccess then
return (s:gsub( '^[\t\r\n\f ]+', '' ):gsub( '[\t\r\n\f ]+$', '' ))
data.title = title
--return string.gsub( s, '^[\t\r\n\f ]*(.-)[\t\r\n\f ]*$', '%1' )
else
return err(title)
end
local docTitleSuccess, docTitle = env:grab('docTitle')
if docTitleSuccess then
data.docTitle = docTitle
else
return err(docTitle)
end
end
-- View, display, edit, and purge links if /doc exists.
local args = require( 'Module:ProcessArgs' ).merge( true )
data.viewLinkDisplay = message('viewLinkDisplay', 'string')
local page = mw.title.getCurrentTitle()
data.editLinkDisplay = message('editLinkDisplay', 'string')
local namespace = page.nsText
data.historyLinkDisplay = message('historyLinkDisplay', 'string')
local docText = trim( args.content or '' )
data.purgeLinkDisplay = message('purgeLinkDisplay', 'string')
if docText == '' then docText = nil end
-- Create link if /doc doesn't exist.
local preload = args[message('preloadArg', 'string')]
if not preload then
if env.subjectSpace == 6 then -- File namespace
preload = message('fileDocpagePreload', 'string')
else
preload = message('docpagePreload', 'string')
end
end
data.preload = preload
data.createLinkDisplay = message('createLinkDisplay', 'string')
return data
end
 
function p.renderStartBoxLinks(data)
-- Render the [view][edit][history][purge] or [create] links.
local ret
local docTitle = data.docTitle
local title = data.title
if docTitle.exists then
local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
local editLink = makeUrlLink(docTitle:fullUrl{action = 'edit'}, data.editLinkDisplay)
local historyLink = makeUrlLink(docTitle:fullUrl{action = 'history'}, data.historyLinkDisplay)
local purgeLink = makeUrlLink(title:fullUrl{action = 'purge'}, data.purgeLinkDisplay)
ret = '[%s] [%s] [%s] [%s]'
ret = ret:gsub('%[', '&#91;') -- Replace square brackets with HTML entities.
ret = ret:gsub('%]', '&#93;')
ret = mw.ustring.format(ret, viewLink, editLink, historyLink, purgeLink)
else
ret = makeUrlLink(docTitle:fullUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
end
end
 
function p.makeStartBoxData(args, env, links)
local subjectSpace = env.subjectSpace
local data = {}
-- Heading
local docPage
local heading = args[message('headingArg', 'string')] -- Blank values are not removed.
local noDoc
if heading == '' then
if docText then
-- Don't display the start box if the heading arg is defined but blank.
docPage = page
return nil
end
if heading then
data.heading = heading
elseif subjectSpace == 10 then -- Template namespace
data.heading = message('documentationIconWikitext', 'string') .. ' ' .. message('templateNamespaceHeading', 'string')
elseif subjectSpace == 828 then -- Module namespace
data.heading = message('documentationIconWikitext', 'string') .. ' ' .. message('moduleNamespaceHeading', 'string')
elseif subjectSpace == 6 then -- File namespace
data.heading = message('fileNamespaceHeading', 'string')
else
else
data.heading = message('otherNamespacesHeading', 'string')
docPage = mw.title.new( args.page or namespace .. ':' .. page.text .. '/' .. defaultDocPage )
noDoc = args.nodoc or not docPage.exists
end
end
local badDoc = args.baddoc
local pageType = mw.ustring.lower( args.type or getType( namespace, page ) )
-- Heading CSS
if not docText and not noDoc then
local headingStyle = args[message('headingStyleArg', 'string')]
f:callParserFunction( '#dplvar:set', '$doc noheader', '1' )
if headingStyle then
docText = trim( f:expandTemplate{ title = ':' .. docPage.fullText }  )
data.headingStyleText = headingStyle
if f:callParserFunction( '#dplvar', '$doc bad' ) == '1' then
elseif subjectSpace == 10 then
badDoc = 1
-- We are in the template or template talk namespaces.
end
data.headingFontWeight = 'bold'
data.headingFontSize = '125%'
if docText == '' then
else
docText = nil
data.headingFontSize = '150%'
noDoc = 1
end
end
end
if docText then
-- [view][edit][history][purge] or [create] links.
docText = '\n' .. docText .. '\n'
if links then
data.linksClass = message('startBoxLinkclasses', 'string')
data.linksId = message('startBoxLinkId', 'string')
data.links = links
end
end
return data
local action = 'edit'
end
local preload = ''
 
local colour = 'EAF4F9'
function p.renderStartBox(data)
local message
-- Renders the start box html.
local category
local sbox = htmlBuilder.create('div')
if noDoc then
sbox
action = 'create'
.css('padding-bottom', '3px')
preload = '&preload=Template:Documentation/preload'
.css('border-bottom', '1px solid #aaa')
colour = 'F9EAEA'
.css('margin-bottom', '1ex')
message = "'''This " .. pageType .. " has no documentation. " ..
.newline()
"If you know how to use this " .. pageType .. ", please create it.'''"
.tag('span')
if not ( args.nocat or namespace == 'User' ) then
.cssText(data.headingStyleText)
category = pageType .. 's with no documentation'
.css('font-weight', data.headingFontWeight)
if not mw.title.new( 'Category:' .. category ).exists then
.css('font-size', data.headingFontSize)
category = 'Pages with no documentation'
.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)
local content = args[message('contentArg', 'string')]
if not content then
local docpage = args[1]
if docpage and mw.title.new(docpage).exists then
local frame = mw.getCurrentFrame()
content = frame:preprocess('{{ ' .. docpage .. ' }}')
else
docpage = env.docspace .. ':' .. env.templatePage .. '/' .. message('docSubpage', 'string')
if mw.title.new(docpage).exists then
local frame = mw.getCurrentFrame()
content = frame:preprocess('{{ ' .. docpage .. ' }}')
end
end
end
end
end
elseif badDoc then
-- The line breaks below are necessary so that "=== Headings ===" at the start and end
colour = 'F9F2EA'
-- of docs are interpreted correctly.
message = "'''This " .. pageType .. "'s documentation needs improving or additional information.'''\n"
return '\n' .. (content or '') .. '\n'  
if not ( args.nocat or namespace == 'User' ) then
end
category = pageType .. 's with bad documentation'
 
if not mw.title.new( 'Category:' .. category ).exists then
----------------------------------------------------------------------------
category = 'Pages with bad documentation'
-- End box
----------------------------------------------------------------------------
 
p.endBox = makeInvokeFunc('_endBox')
 
function p._endBox(args, env)
local title = env.title
local subjectSpace = env.subjectSpace
 
-- Argument processing in {{documentation}}.
local content = args[message('contentArg', 'string')]
local linkBox = args[message('linkBoxArg', 'string')] -- So "link box=off" works.
local docspace = env.docspace
local docname = args[1] -- Other docname, if fed.
local templatePage = env.templatePage
 
-- Argument processing in {{documentation/end box2}}.
local docpageRoot = (docspace or title.nsText) .. ':' .. (templatePage or title.text)
local docpage
if docname then
docpage = docname
else
docpage = docpageRoot .. '/' .. message('docSubpage', 'string')
end
local docTitle = mw.title.new(docpage)
local docExist = docTitle.exists
local docnameFed = args[1] and true
local sandbox = docpageRoot .. '/' .. message('sandboxSubpage', 'string')
local testcases = docpageRoot .. '/' .. message('testcasesSubpage', 'string')
templatePage = title.nsText .. ':' .. templatePage
 
-- Output from {{documentation/end box}}
-- First, 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.
if linkBox == message('linkBoxOff', 'string') or not (docExist or subjectSpace == 2 or subjectSpace == 828 or subjectSpace == 10) then
return nil
end
 
-- Assemble the arguments for {{fmbox}}.
local fmargs = {}
fmargs[message('fmboxIdParam', 'string')] = message('fmboxId', 'string') -- Sets fmargs.id = 'documentation-meta-data'
fmargs[message('fmboxImageParam', 'string')] = message('fmboxImageNone', 'string') -- Sets fmargs.image = 'none'
fmargs[message('fmboxStyleParam', 'string')] = message('fmboxStyle', 'string') -- Sets fmargs.style = 'background-color: #ecfcf4'
fmargs[message('fmboxTextstyleParam', 'string')] = message('fmboxTextstyle', 'string') -- Sets fmargs.textstyle = 'font-style: italic;'
 
-- Assemble the fmbox text field.
local text = ''
if linkBox then
-- Use custom link box content if it is defined.
text = text .. linkBox
else
text = text .. p.makeDocPageBlurb(args, env)
-- Add links to /sandbox and /testcases when appropriate.
if subjectSpace == 2 or subjectSpace == 828 or subjectSpace == 10 then
-- We are in the user, module or template namespaces.
text = text .. p.makeEndBoxExperimentBlurb(args, env)
text = text .. '<br />'
-- Show the categories text, but not if "content" fed or "docname fed" since then it is unclear where to add the categories.
if not content and not docnameFed then
local docPathLink = makeWikilink(docpage, message('docLinkDisplay', 'string'))
text = text .. message('addCategoriesBlurb', 'string', {docPathLink})
end
-- Show the "subpages" link.
if subjectSpace ~= 6 then -- Don't show the link in file space.
local pagetype
if subjectSpace == 10 then
pagetype = message('templatePagetype', 'string')
elseif subjectSpace == 828 then
pagetype = message('modulePagetype', 'string')
else
pagetype = message('defaultPagetype', 'string')
end
text = text .. ' ' .. makeWikilink('Special:PrefixIndex/' .. templatePage .. '/', message('subpagesLinkDisplay', 'string', {pagetype}))
end
-- Show the "print" link if it exists.
local printPage = templatePage .. '/' .. message('printSubpage', 'string')
local printTitle = mw.title.new(printPage)
if printTitle.exists then
local printLink = makeWikilink(printPage, message('printLinkDisplay', 'string'))
text = text .. '<br />' .. message('printBlurb', 'string', {printLink})
.. (message('displayPrintCategory', 'boolean') and makeCategoryLink(message('printCategory', 'string')) or '')
end
end
end
end
end
end
fmargs.text = text
 
local links = {
-- Return the fmbox output.
'[' .. docPage:fullUrl( 'action=edit' .. preload ) .. ' ' .. action .. ']',
return messageBox.main('fmbox', fmargs)
'[' .. docPage:fullUrl( 'action=history' ) .. ' history]',
end
'[' .. page:fullUrl( 'action=purge' ) .. ' purge]'
 
}
function p.makeDocPageBlurb(args, env)
if not noDoc and page ~= docPage then
-- Get the title object.
table.insert( links, 1, '[[' .. docPage.fullText .. '|view]]' )
local success, docTitle = env:grab('docTitle')
if not success then
-- docTitle is the error message.
return docTitle
end
end
-- Make the blurb.
links = mw.html.create( 'span' )
local ret
:css( 'float', 'right' )
if docTitle.exists then
:wikitext( mw.text.nowiki( '[' ), table.concat( links, ' | ' ), mw.text.nowiki( ']' ) )
-- /doc exists; link to it.
local docLink = makeWikilink(docTitle.prefixedText)
local body = mw.html.create( 'div' ):addClass( 'documentation' )
local editUrl = docTitle:fullUrl{action = 'edit'}
body:css{
local editDisplay = message('editLinkDisplay', 'string')
['background-color'] = '#' .. colour,
local editLink = makeUrlLink(editUrl, editDisplay)
border = '1px solid #AAA',
local historyUrl = docTitle:fullUrl{action = 'history'}
padding = '0.8em 1em 0.7em',
local historyDisplay = message('historyLinkDisplay', 'string')
['margin-top'] = '1em',
local historyLink = makeUrlLink(historyUrl, historyDisplay)
clear = 'both'
ret = message('transcludedFromBlurb', 'string', {docLink})
}
.. ' '
.. makeToolbar(editLink, historyLink)
local header = mw.html.create( 'div' )
.. '<br />'
:css{
elseif env.subjectSpace == 828 then
margin = '-0.8em -1em 0.8em',
-- /doc does not exist; ask to create it.
padding = '0.8em 1em 0.7em',
local createUrl = docTitle:fullUrl{action = 'edit', preload = message('modulePreload', 'string')}
['background-color'] = '#EAF4F9',
local createDisplay = message('createLinkDisplay', 'string')
['border-bottom'] = 'inherit'
local createLink = makeUrlLink(createUrl, createDisplay)
}
ret = message('createModuleDocBlurb', 'string', {createLink})
.. '<br />'
header
:node( links )
:tag( 'span' )
:css{
['font-weight'] = 'bold',
['font-size'] = '130%',
['margin-right'] = '1em',
['line-height'] = '1'
}
:wikitext( 'Documentation' )
local codePages = {
module = true,
stylesheet = true,
script = true,
}
if not noDoc and codePages[pageType] then
header
:tag( 'span' )
:css( 'white-space', 'nowrap' )
:wikitext( '[[#the-code|Jump to code ↴]]' )
end
end
return ret
end
body
 
:node( header ):done()
function p.makeEndBoxExperimentBlurb(args, env)
:wikitext( message )
-- Renders the text "Editors can experiment in this template's sandbox (edit | diff) and testcases (edit) pages."
:wikitext( docText )
local subjectSpace = env.subjectSpace
local templatePage = env.templatePage
if not noDoc and page ~= docPage then
-- Get title objects.
body
local sandboxSuccess, sandboxTitle = env:grab('sandboxTitle')
:tag( 'div' )
if not sandboxSuccess then
:css{
return err(sandboxTitle)
margin = '0.7em -1em -0.7em',
['background-color'] = '#EAF4F9',
['border-top'] = 'inherit',
padding = '0.8em 1em 0.7em',
clear = 'both'
}
:node( links )
:wikitext( 'The above documentation is transcluded from [[', docPage.fullText, ']].' )
end
end
local testcasesSuccess, testcasesTitle = env:grab('testcasesTitle')
if not testcasesSuccess then
if category then
return err(testcasesTitle)
body:wikitext( f:expandTemplate{ title = 'Translation category', args = { category, project = '0' } } )
end
end
-- Make links.
local sandboxLinks, testcasesLinks
local anchor = ''
if sandboxTitle.exists then
if not noDoc and pageType ~= 'template' and pageType ~= 'message' then
local sandboxLink = makeWikilink(sandboxTitle.prefixedText, message('sandboxLinkDisplay', 'string'))
anchor = mw.html.create( 'div' ):attr( 'id', 'the-code' )
local sandboxEditLink = makeUrlLink(sandboxTitle:fullUrl{action = 'edit'}, message('sandboxEditLinkDisplay', 'string'))
local compareLink = makeUrlLink(mw.title.new('Special:ComparePages'):fullUrl{page1 = templatePage, page2 = sandbox}, message('compareLinkDisplay', 'string'))
sandboxLinks = sandboxLink .. ' ' .. makeToolbar(sandboxEditLink, compareLink)
else
local sandboxPreload = subjectSpace == 828 and message('moduleSandboxPreload', 'string') or message('templateSandboxPreload', 'string')
local sandboxCreateLink = makeUrlLink(sandboxTitle:fullUrl{action = 'edit', preload = sandboxPreload}, message('sandboxCreateLinkDisplay', 'string'))
local mirrorSummary = message('mirrorEditSummary', 'string', {makeWikilink(templatePage)})
local mirrorLink = makeUrlLink(sandboxTitle:fullUrl{action = 'edit', preload = templatePage, summary = mirrorSummary}, message('mirrorLinkDisplay', 'string'))
sandboxLinks = message('sandboxLinkDisplay', 'string') .. ' ' .. makeToolbar(sandboxCreateLink, mirrorLink)
end
end
if testcasesTitle.exists then
local testcasesLink = makeWikilink(testcasesTitle.prefixedText, message('testcasesLinkDisplay', 'string'))
return tostring( body ) .. tostring( anchor )
local testcasesEditLink = makeUrlLink(testcasesTitle:fullUrl{action = 'edit'}, message('testcasesEditLinkDisplay', 'string'))
testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink)
else
local testcasesPreload = subjectSpace == 828 and message('moduleTestcasesPreload', 'string') or message('templateTestcasesPreload', 'string')
local testcasesCreateLink = makeUrlLink(testcasesTitle:fullUrl{action = 'edit', preload = testcasesPreload}, message('testcasesCreateLinkDisplay', 'string'))
testcasesLinks = message('testcasesLinkDisplay', 'string') .. ' ' .. makeToolbar(testcasesCreateLink)
end
return message(subjectSpace == 828 and 'experimentBlurbModule' or 'experimentBlurbTemplate', 'string', {sandboxLinks, testcasesLinks})
end
 
----------------------------------------------------------------------------
-- Tracking categories
----------------------------------------------------------------------------
 
function p.addTrackingCategories(env)
-- Check if {{documentation}} is transcluded on a /doc or /testcases page.
local title = env.title
local ret = ''
local subpage = title.subpageText
if message('displayStrangeUsageCategory', 'boolean') and (subpage == message('docSubpage', 'string') or subpage == message('testcasesSubpage', 'string')) then
local sort = (title.namespace == 0 and message('strangeUsageCategoryMainspaceSort', 'string') or '') .. title.prefixedText -- Sort on namespace.
ret = ret .. makeCategoryLink(message('strangeUsageCategory', 'string'), sort)
end
return ret
end
end


return p
return p

Latest revision as of 04:10, February 18, 2021

Documentation for this module may be created at Module:Documentation/doc

Script error: Lua error: Internal error: The interpreter exited with status 127.

local p = {}
local defaultDocPage = 'doc'

local getType = function( namespace, page )
	local pageType = 'template'
	if namespace == 'Module' then
		pageType = 'module'
	elseif namespace == 'Widget' then
		pageType = 'widget'
	elseif page.fullText:gsub( '/' .. defaultDocPage .. '$', '' ):find( '%.css$' ) then
		pageType = 'stylesheet'
	elseif page.fullText:gsub( '/' .. defaultDocPage .. '$', '' ):find( '%.js$' ) then
		pageType = 'script'
	elseif namespace == 'MediaWiki' then
		pageType = 'message'
	end
	
	return pageType
end

-- Creating a documentation page or transclution through {{subst:doc}}
function p.create( f )
	local args = require( 'Module:ProcessArgs' ).norm()
	local page = mw.title.getCurrentTitle()
	local docPage = args.page or page.nsText .. ':' .. page.baseText .. '/' .. defaultDocPage
	
	local out
	if not args.content and tostring( page ) == docPage then
		out = f:preprocess( '{{subst:Template:Documentation/preload}}' )
	else
		local templateArgs = {}
		for _, key in ipairs{ 'type', 'page', 'content' } do
			local val = args[key]
			if val then
				if key == 'content' then val = '\n' .. val .. '\n' end
				table.insert( templateArgs, key .. '=' .. val )
			end
		end
		
		out = '{{documentation|' .. table.concat( templateArgs, '|' ) .. '}}'
		out = out:gsub( '|}}', '}}' )
		
		if not args.content then
			out = out .. '\n<!-- Put categories/interwiki on the documentation page -->'
		end
	end
	
	if not mw.isSubsting() then
		out = f:preprocess( out )
		if not args.nocat then
			out = out .. '[[Category:Pages with templates requiring substitution]]'
		end
	end
	
	return out
end

-- Header on the documentation page
function p.docPage( f )
	local args = require( 'Module:ProcessArgs' ).merge( true )
	local badDoc = args.baddoc
	if f:callParserFunction( '#dplvar', '$doc noheader' ) == '1' then
		if badDoc then
			f:callParserFunction( '#dplvar:set', '$doc bad', '1' )
		end
		return
	end
	
	local page = mw.title.getCurrentTitle()
	local namespace = page.nsText
	local pageType = mw.ustring.lower( args.type or getType( namespace, page ) )
	
	local body = mw.html.create( 'div' ):addClass( 'documentation-header' )
	body
		:css{
			['margin-bottom'] = '0.8em',
			padding = '0.8em 1em 0.7em',
			['background-color'] = '#' .. ( badDoc and 'F9F2EA' or 'EAF4F9' ),
			border = '1px solid #AAA'
		}
		:tag( 'div' )
			:css( 'float', 'right' )
			:wikitext( '[[', page:fullUrl( 'action=purge' ), ' purge]]' )
		:done()
		:wikitext(
			'This is the documentation page. It ',
			pageType == 'module' and 'will' or 'should',
			' be transcluded into the main ', pageType, ' page. ',
			'See [[Template:Documentation]] for more information'
		)
	if badDoc then
		body:wikitext( "<br>'''This ", pageType, "'s documentation needs improving or additional information.'''" )
	end
	if not ( args.nocat or namespace == 'User' ) then
		body:wikitext( '[[Category:Documentation pages]]' )
	end
	
	return body
end

-- Wrapper around the documentation on the main page
function p.page( f )
	-- mw.text.trim uses mw.ustring.gsub, which silently fails on large strings
	local function trim( s )
		return (s:gsub( '^[\t\r\n\f ]+', '' ):gsub( '[\t\r\n\f ]+$', '' ))
		--return string.gsub( s, '^[\t\r\n\f ]*(.-)[\t\r\n\f ]*$', '%1' )
	end
	local args = require( 'Module:ProcessArgs' ).merge( true )
	local page = mw.title.getCurrentTitle()
	local namespace = page.nsText
	local docText = trim( args.content or '' )
	if docText == '' then docText = nil end
	
	local docPage
	local noDoc
	if docText then
		docPage = page
	else
		docPage = mw.title.new( args.page or namespace .. ':' .. page.text .. '/' .. defaultDocPage )
		noDoc = args.nodoc or not docPage.exists
	end
	local badDoc = args.baddoc
	local pageType = mw.ustring.lower( args.type or getType( namespace, page ) )
	
	if not docText and not noDoc then
		f:callParserFunction( '#dplvar:set', '$doc noheader', '1' )
		docText = trim( f:expandTemplate{ title = ':' .. docPage.fullText }  )
		if f:callParserFunction( '#dplvar', '$doc bad' ) == '1' then
			badDoc = 1
		end
		
		if docText == '' then
			docText = nil
			noDoc = 1
		end
	end
	if docText then
		docText = '\n' .. docText .. '\n'
	end
	
	local action = 'edit'
	local preload = ''
	local colour = 'EAF4F9'
	local message
	local category
	if noDoc then
		action = 'create'
		preload = '&preload=Template:Documentation/preload'
		colour = 'F9EAEA'
		message = "'''This " .. pageType .. " has no documentation. " ..
			"If you know how to use this " .. pageType .. ", please create it.'''"
		if not ( args.nocat or namespace == 'User' ) then
			category = pageType .. 's with no documentation'
			if not mw.title.new( 'Category:' .. category ).exists then
				category = 'Pages with no documentation'
			end
		end
	elseif badDoc then
		colour = 'F9F2EA'
		message = "'''This " .. pageType .. "'s documentation needs improving or additional information.'''\n"
		if not ( args.nocat or namespace == 'User' ) then
			category = pageType .. 's with bad documentation'
			if not mw.title.new( 'Category:' .. category ).exists then
				category = 'Pages with bad documentation'
			end
		end
	end
	
	local links = {
		'[' .. docPage:fullUrl( 'action=edit' .. preload ) .. ' ' .. action .. ']',
		'[' .. docPage:fullUrl( 'action=history' ) .. ' history]',
		'[' .. page:fullUrl( 'action=purge' ) .. ' purge]'
	}
	if not noDoc and page ~= docPage then
		table.insert( links, 1, '[[' .. docPage.fullText .. '|view]]' )
	end
	links = mw.html.create( 'span' )
		:css( 'float', 'right' )
		:wikitext( mw.text.nowiki( '[' ), table.concat( links, ' | ' ), mw.text.nowiki( ']' ) )
	
	local body = mw.html.create( 'div' ):addClass( 'documentation' )
	body:css{
		['background-color'] = '#' .. colour,
		border = '1px solid #AAA',
		padding = '0.8em 1em 0.7em',
		['margin-top'] = '1em',
		clear = 'both'
	}
	
	local header = mw.html.create( 'div' )
		:css{
			margin = '-0.8em -1em 0.8em',
			padding = '0.8em 1em 0.7em',
			['background-color'] = '#EAF4F9',
			['border-bottom'] = 'inherit'
		}
	
	header
		:node( links )
		:tag( 'span' )
			:css{
				['font-weight'] = 'bold',
				['font-size'] = '130%',
				['margin-right'] = '1em',
				['line-height'] = '1'
			}
			:wikitext( 'Documentation' )
	
	local codePages = {
		module = true,
		stylesheet = true,
		script = true,
	}
	if not noDoc and codePages[pageType] then
		header
			:tag( 'span' )
				:css( 'white-space', 'nowrap' )
				:wikitext( '[[#the-code|Jump to code ↴]]' )
	end
	
	body
		:node( header ):done()
		:wikitext( message )
		:wikitext( docText )
	
	if not noDoc and page ~= docPage then
		body
			:tag( 'div' )
				:css{
					margin = '0.7em -1em -0.7em',
					['background-color'] = '#EAF4F9',
					['border-top'] = 'inherit',
					padding = '0.8em 1em 0.7em',
					clear = 'both'
				}
				:node( links )
				:wikitext( 'The above documentation is transcluded from [[', docPage.fullText, ']].' )
	end
	
	if category then
		body:wikitext( f:expandTemplate{ title = 'Translation category', args = { category, project = '0' } } )
	end
	
	local anchor = ''
	if not noDoc and pageType ~= 'template' and pageType ~= 'message' then
		anchor = mw.html.create( 'div' ):attr( 'id', 'the-code' )
	end
	
	return tostring( body ) .. tostring( anchor )
end

return p