Module:Documentation
Revision as of 11:48, 19 August 2020 by classes>Louis Alarcon (1 revision imported)
Documentation for this module may be created at Module:Documentation/doc
1 -- This module implements {{documentation}}.
2
3 -- Get required modules.
4 local getArgs = require('Module:Arguments').getArgs
5 local messageBox = require('Module:Message box')
6
7 -- Get the config table.
8 local cfg = mw.loadData('Module:Documentation/config')
9 local i18n = mw.loadData('Module:Documentation/i18n')
10 local p = {}
11
12 -- Often-used functions.
13 local ugsub = mw.ustring.gsub
14
15 ----------------------------------------------------------------------------
16 -- Helper functions
17 --
18 -- These are defined as local functions, but are made available in the p
19 -- table for testing purposes.
20 ----------------------------------------------------------------------------
21
22 local function message(cfgKey, valArray, expectType)
23 --[[
24 -- Gets a message from the cfg table and formats it if appropriate.
25 -- The function raises an error if the value from the cfg table is not
26 -- of the type expectType. The default type for expectType is 'string'.
27 -- If the table valArray is present, strings such as $1, $2 etc. in the
28 -- message are substituted with values from the table keys [1], [2] etc.
29 -- For example, if the message "foo-message" had the value 'Foo $2 bar $1.',
30 -- message('foo-message', {'baz', 'qux'}) would return "Foo qux bar baz."
31 --]]
32 local msg = cfg[cfgKey]
33 expectType = expectType or 'string'
34 if type(msg) ~= expectType then
35 error(require('Module:TNT').format('I18n/Documentation', 'cfg-error-msg-type', cfgKey, expectType, type(msg)), 2)
36 end
37 if not valArray then
38 return msg
39 end
40
41 local function getMessageVal(match)
42 match = tonumber(match)
43 return valArray[match] or error(require('Module:TNT').format('I18n/Documentation', 'cfg-error-msg-empty', '$' .. match, cfgKey), 4)
44 end
45
46 local ret = ugsub(msg, '$([1-9][0-9]*)', getMessageVal)
47 return ret
48 end
49
50 p.message = message
51
52 local function makeWikilink(page, display)
53 if display then
54 return mw.ustring.format('[[%s|%s]]', page, display)
55 else
56 return mw.ustring.format('[[%s]]', page)
57 end
58 end
59
60 p.makeWikilink = makeWikilink
61
62 local function makeCategoryLink(cat, sort)
63 local catns = mw.site.namespaces[14].name
64 return makeWikilink(catns .. ':' .. cat, sort)
65 end
66
67 p.makeCategoryLink = makeCategoryLink
68
69 local function makeUrlLink(url, display)
70 return mw.ustring.format('[%s %s]', url, display)
71 end
72
73 p.makeUrlLink = makeUrlLink
74
75 local function makeToolbar(...)
76 local ret = {}
77 local lim = select('#', ...)
78 if lim < 1 then
79 return nil
80 end
81 for i = 1, lim do
82 ret[#ret + 1] = select(i, ...)
83 end
84 return '<small style="font-style: normal;">(' .. table.concat(ret, ' | ') .. ')</small>'
85 end
86
87 p.makeToolbar = makeToolbar
88
89 ----------------------------------------------------------------------------
90 -- Argument processing
91 ----------------------------------------------------------------------------
92
93 local function makeInvokeFunc(funcName)
94 return function (frame)
95 local args = getArgs(frame, {
96 valueFunc = function (key, value)
97 if type(value) == 'string' then
98 value = value:match('^%s*(.-)%s*$') -- Remove whitespace.
99 if key == 'heading' or value ~= '' then
100 return value
101 else
102 return nil
103 end
104 else
105 return value
106 end
107 end
108 })
109 return p[funcName](args)
110 end
111 end
112
113 ----------------------------------------------------------------------------
114 -- Load TemplateStyles
115 ----------------------------------------------------------------------------
116
117 p.main = function(frame)
118 local parent = frame.getParent(frame)
119 local output = p._main(parent.args)
120 return frame:extensionTag{ name='templatestyles', args = { src= message('templatestyles-scr') } } .. frame:preprocess(output)
121 end
122
123 ----------------------------------------------------------------------------
124 -- Main function
125 ----------------------------------------------------------------------------
126
127 function p._main(args)
128 --[[
129 -- This function defines logic flow for the module.
130 -- @args - table of arguments passed by the user
131 --
132 -- Messages:
133 -- 'main-div-id' --> 'template-documentation'
134 -- 'main-div-classes' --> 'template-documentation iezoomfix'
135 --]]
136 local env = p.getEnvironment(args)
137 local root = mw.html.create()
138 root
139 :wikitext(p.protectionTemplate(env))
140 :wikitext(p.sandboxNotice(args, env))
141 -- This div tag is from {{documentation/start box}}, but moving it here
142 -- so that we don't have to worry about unclosed tags.
143 :tag('div')
144 :attr('id', message('main-div-id'))
145 :addClass(message('main-div-class'))
146 :wikitext(p._startBox(args, env))
147 :wikitext(p._content(args, env))
148 :done()
149 :wikitext(p._endBox(args, env))
150 :wikitext(p.addTrackingCategories(env))
151 return tostring(root)
152 end
153
154 ----------------------------------------------------------------------------
155 -- Environment settings
156 ----------------------------------------------------------------------------
157
158 function p.getEnvironment(args)
159 --[[
160 -- Returns a table with information about the environment, including title objects and other namespace- or
161 -- path-related data.
162 -- @args - table of arguments passed by the user
163 --
164 -- Title objects include:
165 -- env.title - the page we are making documentation for (usually the current title)
166 -- env.templateTitle - the template (or module, file, etc.)
167 -- env.docTitle - the /doc subpage.
168 -- env.sandboxTitle - the /sandbox subpage.
169 -- env.testcasesTitle - the /testcases subpage.
170 -- env.printTitle - the print version of the template, located at the /Print subpage.
171 --
172 -- Data includes:
173 -- env.protectionLevels - the protection levels table of the title object.
174 -- env.subjectSpace - the number of the title's subject namespace.
175 -- env.docSpace - the number of the namespace the title puts its documentation in.
176 -- env.docpageBase - the text of the base page of the /doc, /sandbox and /testcases pages, with namespace.
177 -- env.compareUrl - URL of the Special:ComparePages page comparing the sandbox with the template.
178 --
179 -- All table lookups are passed through pcall so that errors are caught. If an error occurs, the value
180 -- returned will be nil.
181 --]]
182
183 local env, envFuncs = {}, {}
184
185 -- Set up the metatable. If triggered we call the corresponding function in the envFuncs table. The value
186 -- returned by that function is memoized in the env table so that we don't call any of the functions
187 -- more than once. (Nils won't be memoized.)
188 setmetatable(env, {
189 __index = function (t, key)
190 local envFunc = envFuncs[key]
191 if envFunc then
192 local success, val = pcall(envFunc)
193 if success then
194 env[key] = val -- Memoise the value.
195 return val
196 end
197 end
198 return nil
199 end
200 })
201
202 function envFuncs.title()
203 -- The title object for the current page, or a test page passed with args.page.
204 local title
205 local titleArg = args.page
206 if titleArg then
207 title = mw.title.new(titleArg)
208 else
209 title = mw.title.getCurrentTitle()
210 end
211 return title
212 end
213
214 function envFuncs.templateTitle()
215 --[[
216 -- The template (or module, etc.) title object.
217 -- Messages:
218 -- 'sandbox-subpage' --> 'sandbox'
219 -- 'testcases-subpage' --> 'testcases'
220 --]]
221 local subjectSpace = env.subjectSpace
222 local title = env.title
223 local subpage = title.subpageText
224 if subpage == message('sandbox-subpage') or subpage == message('testcases-subpage') then
225 return mw.title.makeTitle(subjectSpace, title.baseText)
226 else
227 return mw.title.makeTitle(subjectSpace, title.text)
228 end
229 end
230
231 function envFuncs.docTitle()
232 --[[
233 -- Title object of the /doc subpage.
234 -- Messages:
235 -- 'doc-subpage' --> 'doc'
236 --]]
237 local title = env.title
238 local docname = args[1] -- User-specified doc page.
239 local docpage
240 if docname then
241 docpage = docname
242 else
243 docpage = env.docpageBase .. '/' .. message('doc-subpage')
244 end
245 return mw.title.new(docpage)
246 end
247
248 function envFuncs.sandboxTitle()
249 --[[
250 -- Title object for the /sandbox subpage.
251 -- Messages:
252 -- 'sandbox-subpage' --> 'sandbox'
253 --]]
254 return mw.title.new(env.docpageBase .. '/' .. message('sandbox-subpage'))
255 end
256
257 function envFuncs.testcasesTitle()
258 --[[
259 -- Title object for the /testcases subpage.
260 -- Messages:
261 -- 'testcases-subpage' --> 'testcases'
262 --]]
263 return mw.title.new(env.docpageBase .. '/' .. message('testcases-subpage'))
264 end
265
266 function envFuncs.printTitle()
267 --[[
268 -- Title object for the /Print subpage.
269 -- Messages:
270 -- 'print-subpage' --> 'Print'
271 --]]
272 return env.templateTitle:subPageTitle(message('print-subpage'))
273 end
274
275 function envFuncs.protectionLevels()
276 -- The protection levels table of the title object.
277 return env.title.protectionLevels
278 end
279
280 function envFuncs.subjectSpace()
281 -- The subject namespace number.
282 return mw.site.namespaces[env.title.namespace].subject.id
283 end
284
285 function envFuncs.docSpace()
286 -- The documentation namespace number. For most namespaces this is the same as the
287 -- subject namespace. However, pages in the Article, File, MediaWiki or Category
288 -- namespaces must have their /doc, /sandbox and /testcases pages in talk space.
289 local subjectSpace = env.subjectSpace
290 if subjectSpace == 0 or subjectSpace == 6 or subjectSpace == 8 or subjectSpace == 14 then
291 return subjectSpace + 1
292 else
293 return subjectSpace
294 end
295 end
296
297 function envFuncs.docpageBase()
298 -- The base page of the /doc, /sandbox, and /testcases subpages.
299 -- For some namespaces this is the talk page, rather than the template page.
300 local templateTitle = env.templateTitle
301 local docSpace = env.docSpace
302 local docSpaceText = mw.site.namespaces[docSpace].name
303 -- Assemble the link. docSpace is never the main namespace, so we can hardcode the colon.
304 return docSpaceText .. ':' .. templateTitle.text
305 end
306
307 function envFuncs.compareUrl()
308 -- Diff link between the sandbox and the main template using [[Special:ComparePages]].
309 local templateTitle = env.templateTitle
310 local sandboxTitle = env.sandboxTitle
311 if templateTitle.exists and sandboxTitle.exists then
312 local compareUrl = mw.uri.fullUrl(
313 'Special:ComparePages',
314 {page1 = templateTitle.prefixedText, page2 = sandboxTitle.prefixedText}
315 )
316 return tostring(compareUrl)
317 else
318 return nil
319 end
320 end
321
322 return env
323 end
324
325 ----------------------------------------------------------------------------
326 -- Auxiliary templates
327 ----------------------------------------------------------------------------
328
329 function p.sandboxNotice(args, env)
330 --[=[
331 -- Generates a sandbox notice for display above sandbox pages.
332 -- @args - a table of arguments passed by the user
333 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
334 --
335 -- Messages:
336 -- 'sandbox-notice-image' --> '[[Image:Sandbox.svg|50px|alt=|link=]]'
337 -- 'sandbox-notice-blurb' --> 'This is the $1 for $2.'
338 -- 'sandbox-notice-diff-blurb' --> 'This is the $1 for $2 ($3).'
339 -- 'sandbox-notice-pagetype-template' --> '[[w:Wikipedia:Template test cases|template sandbox]] page'
340 -- 'sandbox-notice-pagetype-module' --> '[[w:Wikipedia:Template test cases|module sandbox]] page'
341 -- 'sandbox-notice-pagetype-other' --> 'sandbox page'
342 -- 'sandbox-notice-compare-link-display' --> 'diff'
343 -- 'sandbox-notice-testcases-blurb' --> 'See also the companion subpage for $1.'
344 -- 'sandbox-notice-testcases-link-display' --> 'test cases'
345 -- 'sandbox-category' --> 'Template sandboxes'
346 --]=]
347 local title = env.title
348 local sandboxTitle = env.sandboxTitle
349 local templateTitle = env.templateTitle
350 local subjectSpace = env.subjectSpace
351 if not (subjectSpace and title and sandboxTitle and templateTitle and mw.title.equals(title, sandboxTitle)) then
352 return nil
353 end
354 -- Build the table of arguments to pass to {{ombox}}. We need just two fields, "image" and "text".
355 local omargs = {}
356 omargs.image = message('sandbox-notice-image')
357 -- Get the text. We start with the opening blurb, which is something like
358 -- "This is the template sandbox for [[Template:Foo]] (diff)."
359 local text = ''
360 local frame = mw.getCurrentFrame()
361 local isPreviewing = frame:preprocess('{{REVISIONID}}') == '' -- True if the page is being previewed.
362 local pagetype
363 if subjectSpace == 10 then
364 pagetype = message('sandbox-notice-pagetype-template')
365 elseif subjectSpace == 828 then
366 pagetype = message('sandbox-notice-pagetype-module')
367 else
368 pagetype = message('sandbox-notice-pagetype-other')
369 end
370 local templateLink = makeWikilink(templateTitle.prefixedText)
371 local compareUrl = env.compareUrl
372 if isPreviewing or not compareUrl then
373 text = text .. message('sandbox-notice-blurb', {pagetype, templateLink})
374 else
375 local compareDisplay = message('sandbox-notice-compare-link-display')
376 local compareLink = makeUrlLink(compareUrl, compareDisplay)
377 text = text .. message('sandbox-notice-diff-blurb', {pagetype, templateLink, compareLink})
378 end
379 -- Get the test cases page blurb if the page exists. This is something like
380 -- "See also the companion subpage for [[Template:Foo/testcases|test cases]]."
381 local testcasesTitle = env.testcasesTitle
382 if testcasesTitle and testcasesTitle.exists then
383 if testcasesTitle.contentModel == "Scribunto" then
384 local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
385 local testcasesRunLinkDisplay = message('sandbox-notice-testcases-run-link-display')
386 local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
387 local testcasesRunLink = makeWikilink(testcasesTitle.talkPageTitle.prefixedText, testcasesRunLinkDisplay)
388 text = text .. '<br />' .. message('sandbox-notice-testcases-run-blurb', {testcasesLink, testcasesRunLink})
389 else
390 local testcasesLinkDisplay = message('sandbox-notice-testcases-link-display')
391 local testcasesLink = makeWikilink(testcasesTitle.prefixedText, testcasesLinkDisplay)
392 text = text .. '<br />' .. message('sandbox-notice-testcases-blurb', {testcasesLink})
393 end
394 end
395 -- Add the sandbox to the sandbox category.
396 text = text .. makeCategoryLink(message('sandbox-category'))
397 omargs.text = text
398 omargs.class = message('sandbox-class')
399 local ret = '<div style="clear: both;"></div>'
400 ret = ret .. messageBox.main('ombox', omargs)
401 return ret
402 end
403
404 function p.protectionTemplate(env)
405 -- Generates the padlock icon in the top right.
406 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
407 -- Messages:
408 -- 'protection-template' --> 'pp-template'
409 -- 'protection-template-args' --> {docusage = 'yes'}
410 local title = env.title
411 local protectionLevels
412 local protectionTemplate = message('protection-template')
413 local namespace = title.namespace
414 if not (protectionTemplate and (namespace == 10 or namespace == 828)) then
415 -- Don't display the protection template if we are not in the template or module namespaces.
416 return nil
417 end
418 protectionLevels = env.protectionLevels
419 if not protectionLevels then
420 return nil
421 end
422 local editLevels = protectionLevels.edit
423 local moveLevels = protectionLevels.move
424 if moveLevels and moveLevels[1] == 'sysop' or editLevels and editLevels[1] then
425 -- The page is full-move protected, or full, template, or semi-protected.
426 local frame = mw.getCurrentFrame()
427 return frame:expandTemplate{title = protectionTemplate, args = message('protection-template-args', nil, 'table')}
428 else
429 return nil
430 end
431 end
432
433 ----------------------------------------------------------------------------
434 -- Start box
435 ----------------------------------------------------------------------------
436
437 p.startBox = makeInvokeFunc('_startBox')
438
439 function p._startBox(args, env)
440 --[[
441 -- This function generates the start box.
442 -- @args - a table of arguments passed by the user
443 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
444 --
445 -- The actual work is done by p.makeStartBoxLinksData and p.renderStartBoxLinks which make
446 -- the [view] [edit] [history] [purge] links, and by p.makeStartBoxData and p.renderStartBox
447 -- which generate the box HTML.
448 --]]
449 env = env or p.getEnvironment(args)
450 local links
451 local content = args.content
452 if not content then
453 -- No need to include the links if the documentation is on the template page itself.
454 local linksData = p.makeStartBoxLinksData(args, env)
455 if linksData then
456 links = p.renderStartBoxLinks(linksData)
457 end
458 end
459 -- Generate the start box html.
460 local data = p.makeStartBoxData(args, env, links)
461 if data then
462 return p.renderStartBox(data)
463 else
464 -- User specified no heading.
465 return nil
466 end
467 end
468
469 function p.makeStartBoxLinksData(args, env)
470 --[[
471 -- Does initial processing of data to make the [view] [edit] [history] [purge] links.
472 -- @args - a table of arguments passed by the user
473 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
474 --
475 -- Messages:
476 -- 'view-link-display' --> 'view'
477 -- 'edit-link-display' --> 'edit'
478 -- 'history-link-display' --> 'history'
479 -- 'purge-link-display' --> 'purge'
480 -- 'file-docpage-preload' --> 'Template:Documentation/preload-filespace'
481 -- 'module-preload' --> 'Template:Documentation/preload-module-doc'
482 -- 'docpage-preload' --> 'Template:Documentation/preload'
483 -- 'create-link-display' --> 'create'
484 --]]
485 local subjectSpace = env.subjectSpace
486 local title = env.title
487 local docTitle = env.docTitle
488 if not title or not docTitle then
489 return nil
490 end
491 if docTitle.isRedirect then
492 docTitle = docTitle.redirectTarget
493 end
494
495 local data = {}
496 data.title = title
497 data.docTitle = docTitle
498 -- View, display, edit, and purge links if /doc exists.
499 data.viewLinkDisplay = i18n['view-link-display']
500 data.editLinkDisplay = i18n['edit-link-display']
501 data.historyLinkDisplay = i18n['history-link-display']
502 data.purgeLinkDisplay = i18n['purge-link-display']
503 -- Create link if /doc doesn't exist.
504 local preload = args.preload
505 if not preload then
506 if subjectSpace == 6 then -- File namespace
507 preload = message('file-docpage-preload')
508 elseif subjectSpace == 828 then -- Module namespace
509 preload = message('module-preload')
510 else
511 preload = message('docpage-preload')
512 end
513 end
514 data.preload = preload
515 data.createLinkDisplay = i18n['create-link-display']
516 return data
517 end
518
519 function p.renderStartBoxLinks(data)
520 --[[
521 -- Generates the [view][edit][history][purge] or [create] links from the data table.
522 -- @data - a table of data generated by p.makeStartBoxLinksData
523 --]]
524
525 local function escapeBrackets(s)
526 -- Escapes square brackets with HTML entities.
527 s = s:gsub('%[', '[') -- Replace square brackets with HTML entities.
528 s = s:gsub('%]', ']')
529 return s
530 end
531
532 local ret
533 local docTitle = data.docTitle
534 local title = data.title
535 if docTitle.exists then
536 local viewLink = makeWikilink(docTitle.prefixedText, data.viewLinkDisplay)
537 local editLink = makeUrlLink(docTitle:fullUrl{action = 'edit'}, data.editLinkDisplay)
538 local historyLink = makeUrlLink(docTitle:fullUrl{action = 'history'}, data.historyLinkDisplay)
539 local purgeLink = makeUrlLink(title:fullUrl{action = 'purge'}, data.purgeLinkDisplay)
540 ret = '[%s] [%s] [%s] [%s]'
541 ret = escapeBrackets(ret)
542 ret = mw.ustring.format(ret, viewLink, editLink, historyLink, purgeLink)
543 else
544 local createLink = makeUrlLink(docTitle:fullUrl{action = 'edit', preload = data.preload}, data.createLinkDisplay)
545 ret = '[%s]'
546 ret = escapeBrackets(ret)
547 ret = mw.ustring.format(ret, createLink)
548 end
549 return ret
550 end
551
552 function p.makeStartBoxData(args, env, links)
553 --[=[
554 -- Does initial processing of data to pass to the start-box render function, p.renderStartBox.
555 -- @args - a table of arguments passed by the user
556 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
557 -- @links - a string containing the [view][edit][history][purge] links - could be nil if there's an error.
558 --
559 -- Messages:
560 -- 'documentation-icon-wikitext' --> '[[File:Test Template Info-Icon - Version (2).svg|50px|link=|alt=Documentation icon]]'
561 -- 'template-namespace-heading' --> 'Template documentation'
562 -- 'module-namespace-heading' --> 'Module documentation'
563 -- 'file-namespace-heading' --> 'Summary'
564 -- 'other-namespaces-heading' --> 'Documentation'
565 -- 'start-box-linkclasses' --> 'mw-editsection-like plainlinks'
566 -- 'start-box-link-id' --> 'doc_editlinks'
567 -- 'testcases-create-link-display' --> 'create'
568 --]=]
569 local subjectSpace = env.subjectSpace
570 if not subjectSpace then
571 -- Default to an "other namespaces" namespace, so that we get at least some output
572 -- if an error occurs.
573 subjectSpace = 2
574 end
575 local data = {}
576
577 -- Heading
578 local heading = args.heading -- Blank values are not removed.
579 if heading == '' then
580 -- Don't display the start box if the heading arg is defined but blank.
581 return nil
582 end
583 if heading then
584 data.heading = heading
585 elseif subjectSpace == 10 then -- Template namespace
586 data.heading = i18n['template-namespace-heading']
587 elseif subjectSpace == 828 then -- Module namespace
588 data.heading = i18n['module-namespace-heading']
589 elseif subjectSpace == 6 then -- File namespace
590 data.heading = i18n['file-namespace-heading']
591 else
592 data.heading = i18n['other-namespaces-heading']
593 end
594
595 -- Data for the [view][edit][history][purge] or [create] links.
596 if links then
597 data.linksClass = message('start-box-linkclasses')
598 data.linksId = message('start-box-link-id')
599 data.links = links
600 end
601
602 return data
603 end
604
605 function p.renderStartBox(data)
606 -- Renders the start box html.
607 -- @data - a table of data generated by p.makeStartBoxData.
608 local sbox = mw.html.create('div')
609 sbox
610 :addClass(message('header-div-class'))
611 :tag('div')
612 :addClass(message('heading-div-class'))
613 :wikitext(data.heading)
614 local links = data.links
615 if links then
616 sbox
617 :tag('div')
618 :addClass(data.linksClass)
619 :attr('id', data.linksId)
620 :wikitext(links)
621 end
622 return tostring(sbox)
623 end
624
625 ----------------------------------------------------------------------------
626 -- Documentation content
627 ----------------------------------------------------------------------------
628
629 p.content = makeInvokeFunc('_content')
630
631 function p._content(args, env)
632 -- Displays the documentation contents
633 -- @args - a table of arguments passed by the user
634 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
635 env = env or p.getEnvironment(args)
636 local docTitle = env.docTitle
637 local content = args.content
638 if not content and docTitle and docTitle.exists then
639 content = args._content or mw.getCurrentFrame():expandTemplate{title = docTitle}
640 end
641 -- The line breaks below are necessary so that "=== Headings ===" at the start and end
642 -- of docs are interpreted correctly.
643 local cbox = mw.html.create('div')
644 cbox
645 :addClass(message('content-div-class'))
646 :wikitext('\n' .. (content or '') .. '\n')
647 return tostring(cbox)
648 end
649
650 p.contentTitle = makeInvokeFunc('_contentTitle')
651
652 function p._contentTitle(args, env)
653 env = env or p.getEnvironment(args)
654 local docTitle = env.docTitle
655 if not args.content and docTitle and docTitle.exists then
656 return docTitle.prefixedText
657 else
658 return ''
659 end
660 end
661
662 ----------------------------------------------------------------------------
663 -- End box
664 ----------------------------------------------------------------------------
665
666 p.endBox = makeInvokeFunc('_endBox')
667
668 function p._endBox(args, env)
669 --[=[
670 -- This function generates the end box (also known as the link box).
671 -- @args - a table of arguments passed by the user
672 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
673 --]=]
674
675 -- Get environment data.
676 env = env or p.getEnvironment(args)
677 local subjectSpace = env.subjectSpace
678 local docTitle = env.docTitle
679 if not subjectSpace or not docTitle then
680 return nil
681 end
682
683 -- Check whether we should output the end box at all. Add the end
684 -- box by default if the documentation exists or if we are in the
685 -- user, module or template namespaces.
686 local linkBox = args['link box']
687 if linkBox == 'off'
688 or not (
689 docTitle.exists
690 or subjectSpace == 2
691 or subjectSpace == 828
692 or subjectSpace == 10
693 )
694 then
695 return nil
696 end
697
698 -- Assemble the footer text field.
699 local text = ''
700 if linkBox then
701 text = text .. linkBox
702 else
703 text = text .. (p.makeDocPageBlurb(args, env) or '') -- "This documentation is transcluded from [[Foo]]."
704 if subjectSpace == 2 or subjectSpace == 10 or subjectSpace == 828 then
705 -- We are in the user, template or module namespaces.
706 -- Add sandbox and testcases links.
707 -- "Editors can experiment in this template's sandbox and testcases pages."
708 text = text .. (p.makeExperimentBlurb(args, env) or '')
709 text = text .. '<br />'
710 if not args.content and not args[1] then
711 -- "Please add categories to the /doc subpage."
712 -- Don't show this message with inline docs or with an explicitly specified doc page,
713 -- as then it is unclear where to add the categories.
714 text = text .. (p.makeCategoriesBlurb(args, env) or '')
715 end
716 text = text .. ' ' .. (p.makeSubpagesBlurb(args, env) or '') --"Subpages of this template"
717 local printBlurb = p.makePrintBlurb(args, env) -- Two-line blurb about print versions of templates.
718 if printBlurb then
719 text = text .. '<br />' .. printBlurb
720 end
721 end
722 end
723
724 local ebox = mw.html.create('div')
725 ebox
726 :addClass(message('footer-div-class'))
727 :wikitext(text)
728 return tostring(ebox)
729 end
730
731 function p.makeDocPageBlurb(args, env)
732 --[=[
733 -- Makes the blurb "This documentation is transcluded from [[Template:Foo]] (edit, history)".
734 -- @args - a table of arguments passed by the user
735 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
736 --
737 -- Messages:
738 -- 'edit-link-display' --> 'edit'
739 -- 'history-link-display' --> 'history'
740 -- 'transcluded-from-blurb' -->
741 -- 'The above [[w:Wikipedia:Template documentation|documentation]]
742 -- is [[w:Wikipedia:Transclusion|transcluded]] from $1.'
743 -- 'module-preload' --> 'Template:Documentation/preload-module-doc'
744 -- 'create-link-display' --> 'create'
745 -- 'create-module-doc-blurb' -->
746 -- 'You might want to $1 a documentation page for this [[w:Wikipedia:Lua|Scribunto module]].'
747 --]=]
748 local docTitle = env.docTitle
749 if not docTitle or args.content then
750 return nil
751 end
752 local ret
753 if docTitle.exists then
754 -- /doc exists; link to it.
755 local docLink = makeWikilink(docTitle.prefixedText)
756 local editUrl = docTitle:fullUrl{action = 'edit'}
757 local editDisplay = i18n['edit-link-display']
758 local editLink = makeUrlLink(editUrl, editDisplay)
759 local historyUrl = docTitle:fullUrl{action = 'history'}
760 local historyDisplay = i18n['history-link-display']
761 local historyLink = makeUrlLink(historyUrl, historyDisplay)
762 ret = message('transcluded-from-blurb', {docLink})
763 .. ' '
764 .. makeToolbar(editLink, historyLink)
765 .. '<br />'
766 elseif env.subjectSpace == 828 then
767 -- /doc does not exist; ask to create it.
768 local createUrl = docTitle:fullUrl{action = 'edit', preload = message('module-preload')}
769 local createDisplay = i18n['create-link-display']
770 local createLink = makeUrlLink(createUrl, createDisplay)
771 ret = message('create-module-doc-blurb', {createLink})
772 .. '<br />'
773 end
774 return ret
775 end
776
777 function p.makeExperimentBlurb(args, env)
778 --[[
779 -- Renders the text "Editors can experiment in this template's sandbox (edit | diff) and testcases (edit) pages."
780 -- @args - a table of arguments passed by the user
781 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
782 --
783 -- Messages:
784 -- 'sandbox-link-display' --> 'sandbox'
785 -- 'sandbox-edit-link-display' --> 'edit'
786 -- 'compare-link-display' --> 'diff'
787 -- 'module-sandbox-preload' --> 'Template:Documentation/preload-module-sandbox'
788 -- 'template-sandbox-preload' --> 'Template:Documentation/preload-sandbox'
789 -- 'sandbox-create-link-display' --> 'create'
790 -- 'mirror-edit-summary' --> 'Create sandbox version of $1'
791 -- 'mirror-link-display' --> 'mirror'
792 -- 'mirror-link-preload' --> 'Template:Documentation/mirror'
793 -- 'sandbox-link-display' --> 'sandbox'
794 -- 'testcases-link-display' --> 'testcases'
795 -- 'testcases-edit-link-display'--> 'edit'
796 -- 'template-sandbox-preload' --> 'Template:Documentation/preload-sandbox'
797 -- 'testcases-create-link-display' --> 'create'
798 -- 'testcases-link-display' --> 'testcases'
799 -- 'testcases-edit-link-display' --> 'edit'
800 -- 'module-testcases-preload' --> 'Template:Documentation/preload-module-testcases'
801 -- 'template-testcases-preload' --> 'Template:Documentation/preload-testcases'
802 -- 'experiment-blurb-module' --> 'Editors can experiment in this module's $1 and $2 pages.'
803 -- 'experiment-blurb-template' --> 'Editors can experiment in this template's $1 and $2 pages.'
804 --]]
805 local subjectSpace = env.subjectSpace
806 local templateTitle = env.templateTitle
807 local sandboxTitle = env.sandboxTitle
808 local testcasesTitle = env.testcasesTitle
809 local templatePage = templateTitle.prefixedText
810 if not subjectSpace or not templateTitle or not sandboxTitle or not testcasesTitle then
811 return nil
812 end
813 -- Make links.
814 local sandboxLinks, testcasesLinks
815 if sandboxTitle.exists then
816 local sandboxPage = sandboxTitle.prefixedText
817 local sandboxDisplay = message('sandbox-link-display')
818 local sandboxLink = makeWikilink(sandboxPage, sandboxDisplay)
819 local sandboxEditUrl = sandboxTitle:fullUrl{action = 'edit'}
820 local sandboxEditDisplay = message('sandbox-edit-link-display')
821 local sandboxEditLink = makeUrlLink(sandboxEditUrl, sandboxEditDisplay)
822 local compareUrl = env.compareUrl
823 local compareLink
824 if compareUrl then
825 local compareDisplay = message('compare-link-display')
826 compareLink = makeUrlLink(compareUrl, compareDisplay)
827 end
828 sandboxLinks = sandboxLink .. ' ' .. makeToolbar(sandboxEditLink, compareLink)
829 else
830 local sandboxPreload
831 if subjectSpace == 828 then
832 sandboxPreload = message('module-sandbox-preload')
833 else
834 sandboxPreload = message('template-sandbox-preload')
835 end
836 local sandboxCreateUrl = sandboxTitle:fullUrl{action = 'edit', preload = sandboxPreload}
837 local sandboxCreateDisplay = message('sandbox-create-link-display')
838 local sandboxCreateLink = makeUrlLink(sandboxCreateUrl, sandboxCreateDisplay)
839 local mirrorSummary = message('mirror-edit-summary', {makeWikilink(templatePage)})
840 local mirrorPreload = message('mirror-link-preload')
841 local mirrorUrl = sandboxTitle:fullUrl{action = 'edit', preload = mirrorPreload, summary = mirrorSummary}
842 local mirrorDisplay = message('mirror-link-display')
843 local mirrorLink = makeUrlLink(mirrorUrl, mirrorDisplay)
844 sandboxLinks = message('sandbox-link-display') .. ' ' .. makeToolbar(sandboxCreateLink, mirrorLink)
845 end
846 if testcasesTitle.exists then
847 local testcasesPage = testcasesTitle.prefixedText
848 local testcasesDisplay = message('testcases-link-display')
849 local testcasesLink = makeWikilink(testcasesPage, testcasesDisplay)
850 local testcasesEditUrl = testcasesTitle:fullUrl{action = 'edit'}
851 local testcasesEditDisplay = message('testcases-edit-link-display')
852 local testcasesEditLink = makeUrlLink(testcasesEditUrl, testcasesEditDisplay)
853 testcasesLinks = testcasesLink .. ' ' .. makeToolbar(testcasesEditLink)
854 else
855 local testcasesPreload
856 if subjectSpace == 828 then
857 testcasesPreload = message('module-testcases-preload')
858 else
859 testcasesPreload = message('template-testcases-preload')
860 end
861 local testcasesCreateUrl = testcasesTitle:fullUrl{action = 'edit', preload = testcasesPreload}
862 local testcasesCreateDisplay = message('testcases-create-link-display')
863 local testcasesCreateLink = makeUrlLink(testcasesCreateUrl, testcasesCreateDisplay)
864 testcasesLinks = message('testcases-link-display') .. ' ' .. makeToolbar(testcasesCreateLink)
865 end
866 local messageName
867 if subjectSpace == 828 then
868 messageName = 'experiment-blurb-module'
869 else
870 messageName = 'experiment-blurb-template'
871 end
872 return message(messageName, {sandboxLinks, testcasesLinks})
873 end
874
875 function p.makeCategoriesBlurb(args, env)
876 --[[
877 -- Generates the text "Please add categories to the /doc subpage."
878 -- @args - a table of arguments passed by the user
879 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
880 -- Messages:
881 -- 'doc-link-display' --> '/doc'
882 -- 'add-categories-blurb' --> 'Please add categories to the $1 subpage.'
883 --]]
884 local docTitle = env.docTitle
885 if not docTitle then
886 return nil
887 end
888 local docPathLink = makeWikilink(docTitle.prefixedText, message('doc-link-display'))
889 return message('add-categories-blurb', {docPathLink})
890 end
891
892 function p.makeSubpagesBlurb(args, env)
893 --[[
894 -- Generates the "Subpages of this template" link.
895 -- @args - a table of arguments passed by the user
896 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
897
898 -- Messages:
899 -- 'template-pagetype' --> 'template'
900 -- 'module-pagetype' --> 'module'
901 -- 'default-pagetype' --> 'page'
902 -- 'subpages-link-display' --> 'Subpages of this $1'
903 --]]
904 local subjectSpace = env.subjectSpace
905 local templateTitle = env.templateTitle
906 if not subjectSpace or not templateTitle then
907 return nil
908 end
909 local pagetype
910 if subjectSpace == 10 then
911 pagetype = message('template-pagetype')
912 elseif subjectSpace == 828 then
913 pagetype = message('module-pagetype')
914 else
915 pagetype = message('default-pagetype')
916 end
917 local subpagesLink = makeWikilink(
918 'Special:PrefixIndex/' .. templateTitle.prefixedText .. '/',
919 message('subpages-link-display', {pagetype})
920 )
921 return message('subpages-blurb', {subpagesLink})
922 end
923
924 function p.makePrintBlurb(args, env)
925 --[=[
926 -- Generates the blurb displayed when there is a print version of the template available.
927 -- @args - a table of arguments passed by the user
928 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
929 --
930 -- Messages:
931 -- 'print-link-display' --> '/Print'
932 -- 'print-blurb' --> 'A [[Help:Books/for experts#Improving the book layout|print version]]'
933 -- .. ' of this template exists at $1.'
934 -- .. ' If you make a change to this template, please update the print version as well.'
935 -- 'display-print-category' --> true
936 -- 'print-category' --> 'Templates with print versions'
937 --]=]
938 local printTitle = env.printTitle
939 if not printTitle then
940 return nil
941 end
942 local ret
943 if printTitle.exists then
944 local printLink = makeWikilink(printTitle.prefixedText, message('print-link-display'))
945 ret = message('print-blurb', {printLink})
946 local displayPrintCategory = message('display-print-category', nil, 'boolean')
947 if displayPrintCategory then
948 ret = ret .. makeCategoryLink(message('print-category'))
949 end
950 end
951 return ret
952 end
953
954 ----------------------------------------------------------------------------
955 -- Tracking categories
956 ----------------------------------------------------------------------------
957
958 function p.addTrackingCategories(env)
959 --[[
960 -- Check if {{documentation}} is transcluded on a /doc or /testcases page.
961 -- @env - environment table containing title objects, etc., generated with p.getEnvironment
962
963 -- Messages:
964 -- 'display-strange-usage-category' --> true
965 -- 'doc-subpage' --> 'doc'
966 -- 'testcases-subpage' --> 'testcases'
967 -- 'strange-usage-category' --> 'Wikipedia pages with strange ((documentation)) usage'
968 --
969 -- /testcases pages in the module namespace are not categorised, as they may have
970 -- {{documentation}} transcluded automatically.
971 --]]
972 local title = env.title
973 local subjectSpace = env.subjectSpace
974 if not title or not subjectSpace then
975 return nil
976 end
977 local subpage = title.subpageText
978 local ret = ''
979 if message('display-strange-usage-category', nil, 'boolean')
980 and (
981 subpage == message('doc-subpage')
982 or subjectSpace ~= 828 and subpage == message('testcases-subpage')
983 )
984 then
985 ret = ret .. makeCategoryLink(message('strange-usage-category'))
986 end
987 return ret
988 end
989
990 return p