text:
Module:Hatnote

--                             Module:Hatnote                                -- --                                                                           -- -- This module produces hatnote links and links to related articles. It      -- -- implements the and  meta-templates and includes -- -- helper functions for other Lua hatnote modules. --

local libraryUtil = require('libraryUtil') local checkType = libraryUtil.checkType local checkTypeForNamedArg = libraryUtil.checkTypeForNamedArg local mArguments -- lazily initialise Module:Arguments local yesno -- lazily initialise Module:Yesno local formatLink -- lazily initialise Module:Format link ._formatLink

local p = {}

-- Helper functions

local function getArgs(frame) -- Fetches the arguments from the parent frame. Whitespace is trimmed and -- blanks are removed. mArguments = require('Module:Arguments') return mArguments.getArgs(frame, {parentOnly = true}) end

local function removeInitialColon(s) -- Removes the initial colon from a string, if present. return s:match('^:?(.*)') end

function p.defaultClasses(inline) -- Provides the default hatnote classes as a space-separated string; useful -- for hatnote-manipulation modules like Module:Hatnote group. return (inline == 1 and 'hatnote-inline' or 'hatnote') .. ' ' ..		'navigation-not-searchable' end

function p.disambiguate(page, disambiguator) -- Formats a page title with a disambiguation parenthetical, -- i.e. "Example" → "Example (disambiguation)". checkType('disambiguate', 1, page, 'string') checkType('disambiguate', 2, disambiguator, 'string', true) disambiguator = disambiguator or 'disambiguation' return mw.ustring.format('%s (%s)', page, disambiguator) end

function p.findNamespaceId(link, removeColon) -- Finds the namespace id (namespace number) of a link or a pagename. This -- function will not work if the link is enclosed in double brackets. Colons -- are trimmed from the start of the link by default. To skip colon -- trimming, set the removeColon parameter to false. checkType('findNamespaceId', 1, link, 'string') checkType('findNamespaceId', 2, removeColon, 'boolean', true) if removeColon ~= false then link = removeInitialColon(link) end local namespace = link:match('^(.-):') if namespace then local nsTable = mw.site.namespaces[namespace] if nsTable then return nsTable.id		end end return 0 end

function p.makeWikitextError(msg, helpLink, addTrackingCategory, title) -- Formats an error message to be returned to wikitext. If	-- addTrackingCategory is not false after being returned from -- Module:Yesno, and if we are not on a talk page, a tracking category -- is added. checkType('makeWikitextError', 1, msg, 'string') checkType('makeWikitextError', 2, helpLink, 'string', true) yesno = require('Module:Yesno') title = title or mw.title.getCurrentTitle -- Make the help link text. local helpText if helpLink then helpText = ' (help)' else helpText = '' end -- Make the category text. local category if not title.isTalkPage -- Don't categorise talk pages and title.namespace ~= 2 -- Don't categorise userspace and yesno(addTrackingCategory) ~= false -- Allow opting out then category = 'Hatnote templates with errors' category = mw.ustring.format(			'%s:%s',			mw.site.namespaces[14].name,			category		) else category = '' end return mw.ustring.format(		' Error: %s%s. %s',		msg,		helpText,		category	) end

local curNs = mw.title.getCurrentTitle.namespace p.missingTargetCat = --Default missing target category, exported for use in related modules ((curNs == 0) or (curNs == 14)) and 'Articles with hatnote templates targeting a nonexistent page' or nil

function p.quote(title) --Wraps titles in quotation marks. If the title starts/ends with a quotation --mark, kerns that side as with local quotationMarks = { ["'"]=true, ['"']=true, ['“']=true, ["‘"]=true, ['”']=true, ["’"]=true	}	local quoteLeft, quoteRight = -- Test if start/end are quotation marks		quotationMarks[string.sub(title, 1,  1)],		quotationMarks[string.sub(title, -1, -1)]	if quoteLeft or quoteRight then		title = mw.html.create("span"):wikitext(title)	end	if quoteLeft  then title:css("padding-left",  "0.15em") end	if quoteRight then title:css("padding-right", "0.15em") end	return '"' .. tostring(title) .. '"' end

-- Hatnote -- -- Produces standard hatnote text. Implements the template.

function p.hatnote(frame) local args = getArgs(frame) local s = args[1] if not s then return p.makeWikitextError(			'no text specified',			'Template:Hatnote#Errors',			args.category		) end return p._hatnote(s, {		extraclasses = args.extraclasses,		selfref = args.selfref	}) end

function p._hatnote(s, options) checkType('_hatnote', 1, s, 'string') checkType('_hatnote', 2, options, 'table', true) options = options or {} local inline = options.inline local hatnote = mw.html.create(inline == 1 and 'span' or 'div') local extraclasses if type(options.extraclasses) == 'string' then extraclasses = options.extraclasses end

hatnote :attr('role', 'note') :addClass(p.defaultClasses(inline)) :addClass(extraclasses) :addClass(options.selfref and 'selfref' or nil) :wikitext(s)

return mw.getCurrentFrame:extensionTag{ name = 'templatestyles', args = { src = 'Module:Hatnote/styles.css' } } .. tostring(hatnote) end

return p

title: Module:Hatnote


text:
Module:Section link

-- This module implements. require('strict');

local checkType = require('libraryUtil').checkType

local p = {}

local function makeSectionLink(page, section, display) display = display or section page = page or '' -- MediaWiki doesn't allow these in `page`, so only need to do for `section` if type(section) == 'string' then section = string.gsub(section, "{", "{") section = string.gsub(section, "}", "}") end return string.format('%s', page, section, display) end

local function normalizeTitle(title) title = mw.ustring.gsub(mw.ustring.gsub(title, "'", ""), '"', '')	title = mw.ustring.gsub(title, "%b<>", "")	return mw.title.new(title).prefixedText end

function p._main(page, sections, options, title) -- Validate input. checkType('_main', 1, page, 'string', true) checkType('_main', 3, options, 'table', true) if sections == nil then sections = {} elseif type(sections) == 'string' then sections = {sections} elseif type(sections) ~= 'table' then error(string.format( "type error in argument #2 to '_main' " .. "(string, table or nil expected, got %s)", type(sections) ), 2)	end options = options or {} title = title or mw.title.getCurrentTitle

-- Deal with blank page names elegantly if page and not page:find('%S') then page = nil options.nopage = true end

-- Make the link(s). local isShowingPage = not options.nopage if #sections <= 1 then local linkPage = page or '' local section = sections[1] or 'Notes' local display = '§ ' .. section if isShowingPage then page = page or title.prefixedText if options.display and options.display ~= '' then if normalizeTitle(options.display) == normalizeTitle(page) then display = options.display .. ' ' .. display else error(string.format( 'Display title "%s" was ignored since it is ' .. "not equivalent to the page's actual title", options.display ), 0)				end else display = page .. ' ' .. display end end return makeSectionLink(linkPage, section, display) else -- Multiple sections. First, make a list of the links to display. local ret = {} for i, section in ipairs(sections) do			ret[i] = makeSectionLink(page, section) end

-- Assemble the list of links into a string with mw.text.listToText. -- We use the default separator for mw.text.listToText, but a custom -- conjunction. There is also a special case conjunction if we only -- have two links. local conjunction if #sections == 2 then conjunction = ' and ' else conjunction = ', and ' end ret = mw.text.listToText(ret, nil, conjunction)

-- Add the intro text. local intro = '§§ ' if isShowingPage then intro = (page or title.prefixedText) .. ' ' .. intro end ret = intro .. ret

return ret end end

function p.main(frame) local yesno = require('Module:Yesno') local args = require('Module:Arguments').getArgs(frame, {		wrappers = 'Template:Section link',		valueFunc = function (key, value)			value = value:match('^%s*(.-)%s*$') -- Trim whitespace			-- Allow blank first parameters, as the wikitext template does this.			if value ~= '' or key == 1 then				return value			end		end	})

for k, v in pairs(args) do													-- replace underscores in the positional parameter values if 'number' == type(k) then if not yesno (args['keep-underscores']) then						-- unless |keep-underscores=yes args[k] = mw.uri.decode (v, 'WIKI');							-- percent-decode; replace underscores with space characters else args[k] = mw.uri.decode (v, 'PATH');							-- percent-decode; retain underscores end end end

-- Sort the arguments. local page local sections, options = {}, {} for k, v in pairs(args) do		if k == 1 then -- Doing this in the loop because of a bug in Module:Arguments -- when using pairs with deleted arguments. page = mw.text.decode(v, true) elseif type(k) == 'number' then sections[k] = v		else options[k] = v		end end options.nopage = yesno (options.nopage);									-- make boolean -- Extract section from page, if present if page then local p, s = page:match('^(.-)#(.*)$') if p then page, sections[1] = p, s end end

-- Compress the sections array. local function compressArray(t) local nums, ret = {}, {} for num in pairs(t) do			nums[#nums + 1] = num end table.sort(nums) for i, num in ipairs(nums) do			ret[i] = t[num] end return ret end sections = compressArray(sections)

return p._main(page, sections, options) end

return p

license: Creative Commons - Attribution Share-Alike - https://creativecommons.org/licenses/by-sa/4.0/

title: Module:Section link


text:
Module:Section link/doc

This module creates links to sections, nicely formatted with the "§" symbol instead of the default "#".

From wikitext
From wikitext, this module should be used via the template section link. Please see the template page for documentation.

From Lua
First, load the module:

You can then make section links via the _main function.

Parameters: All parameters are optional.
 * page - the page name to link to. Defaults to the full page name of title, or the current title if that is not specified.
 * sections - an array of section names to link to, or a string to link to just one section name.
 * options - a table of options. Accepts the following fields:
 * nopage - set this to true to avoid displaying the base page name in links.
 * title - a default mw.title object to use instead of the current title. Intended for testing purposes.

title: Module:Section link/doc


text:
Template:Collapse top/doc

The template (or ), and its paired template  (or ), are used for placing a collapse box around a talk page discussion, especially when the content contains complex wikimarkup such as tables. For very simple content, the one-piece template can be used instead.

These templates should only be used in accordance with the Refactoring guideline; they should never be used to end a discussion over the objections of other editors, except in cases of unambiguous disruptive editing.

Do not hide content in articles. This violates the and Accessibility guidelines.

Usage
Place (or ), and  (or ), around the text to be collapsed. For example:

Sample contents text produces:

Sample contents text

should always be placed on its own line. Do not place any characters before the template on this line. (This means that if you use the Reply Tool, you need to remember to manually remove the colon or colons it inserts at the start of each line to maintain proper indentation after replying)

Parameters
This template takes the following parameters, all of which are optional. They are case-sensitive. Those that take CSS measurements require them in CSS format (e.g., not  ).

 * 1, title, reason, header, heading, result, or first unnamed parameter : Will give the collapsed box a title, which occurs on the same line as the show link and is always visible. It defaults to "Extended content". For example,  or  . Note: The shorter, unnamed markup will not work if the title value contain an equals  character.
 * yes: Will display a default warning line under the main title which reads "The following is a closed debate. Please do not modify it." Any value supplied to this parameter will have this effect (i.e. no will not work as expected).
 * 2 or second unnamed parameter : This is optional warning-line text. It will override the standard warning line above; it is not necessary to also use yes in this case, though doing so is harmless.
 * yes: Will align the title along the left margin. By default, text is centered, specifically between the left edge of the green box and the left edge of the "show" link. Any value will enable this parameter (i.e. no will not work as expected); nor is there a right parameter.
 * yes or no: Will leave the material uncollapsed with the border and coloring. Default is to collapse the material. Any value will have this effect (i.e. no and yes will not work as expected).
 * bg: Sets the background color of the collapsed material. Defaults to, a green hue. Named colors are listed at List of colors. For example,   or   (HTML hex color codes require the leading  ).
 * fc: Sets the font color of the title of the collapsible bar. Defaults to inheriting the current text color of the context. See bg, above, for details on color options.
 * border: Sets the width of the border line on the collapsed material. defaults to . For example,  ; going much thicker than this is not very useful.
 * b-color: Sets the border color. defaults to  . See bg, above, for details on color options.
 * padding: Sets the padding (distance from borders) on the collapsed material inside the colored area. Defaults to.
 * width: Sets the width of the overall template relative to the page (or a block element containing the collapse box). This should virtually always be given as a percentage, e.g. 50%, or in relative em units, e.g. 30em. Pixel-based values should be avoided, as they are effectively meaningless – the result will be different depending on each user's browser and local CSS settings (which browser and operating system it is, zoom level, font sizes, etc.).
 * border2: Sets the properties of the border of the box that appears when template is expanded; defaults to  (there is no provision to change from a solid line). For example,   (only width or color will be changed if only one value is supplied).   See bg, above, for details on color options.
 * bg2: Sets the background color of the box that appears when template is expanded; defaults to  . See bg, above, for details on color options.
 * indent: Indents the box from the left of the page. Defaults to no indentation. Each  in talk page markup is approximately equivalent to   of indent (e.g., to match   indentation level, use 6.4em. You can also use a percentage value. Pixel-based values should be avoided (see width, above, for why).
 * clear: In some situations you may not want the default  CSS to apply, which puts the collapse box below any left- or right-floated content within the same HTML block. In this case, you can use none, right, or left, as needed.

Examples

 * Adding a box title (if omitted, default is 'Extended content') –

 * Adding a standard warning line –

 * Adding a custom warning line –

 * Aligning box title along left margin –

 * Changing background color –

 * Adding extra padding –

 * Archiving a section: the markup below:

Section header
Sample contents text must be rewritten as: Sample contents text The end result:

Sample contents text

TemplateData
{	"params": { "1": {			"aliases": [ "title", "heading", "header", "reason", "result" ],			"label": "Title", "description": "Main title of collapsed box", "example": "This is the title text", "required": true },		"2": {			"label": "Custom warning line", "description": "Will override the standard warning line, and make the 'warning' parameter unnecessary", "example": "This is a custom warning line", "type": "string" },		"indent": { "label": "Indent (px or em)", "description": "Indents the box from the left of the page", "type": "unknown", "autovalue": "0px" },		"expand": { "aliases": [ "collapse" ],			"description": "Using expand=yes or collapse=no will leave the material uncollapsed with the border and coloring", "example": "true", "type": "string", "autovalue": "" },		"border": { "label": "Border width (px)", "description": "Sets the width of the border line on the collapsed material", "example": "2px", "default": "1px", "autovalue": "" },		"b-color": { "label": "Border color", "description": "Sets the border color", "example": "#F0F2F5", "default": "Silver" },		"width": { "label": "Template width (% or em)", "description": "Sets the width of the overall template", "example": "50%" },		"bg": { "label": "Collapsed material background color", "description": "Sets the background color of the collapsed material", "example": "#F0F2F5", "default": "#CFC" },		"left": { "label": "Alight along the left margin (true or blank)", "description": "Will align the 'parameter 1 title' along the left margin", "example": "true", "type": "string" },		"fc": { "label": "Title font color", "description": "Sets the font color of the title of the collapsible bar", "example": "#F0F2F5", "default": "Black" },		"warning": { "label": "Warning (true or blank)", "description": "Will display a default warning line under the main title which reads \"The following is a closed debate. Please do not modify it.\"", "example": "true" },		"border2": { "label": "Expanded box border size & color", "description": "Sets the border of the box that appears when template is expanded", "example": "2px", "default": "1px silver" },		"padding": { "label": "Padding (px)", "description": "Sets the padding on the collapsed material in the colored area", "example": "16px", "default": "8px" },		"bg2": { "label": "Expanded box color", "description": "Sets background of the box that appears when template is expanded", "example": "#F0F2F5", "default": "white" }	},	"description": "Use in conjunction with . Will collapse text in between the two templates." }

Redirects
To Collapse top: To Collapse bottom:
 * cot
 * ctop
 * DAT
 * cob
 * cbot

title: Template:Collapse top/doc


text: Template:Collapsible templates

title: Template:Collapsible templates


text:
Template:Terminate sentence/doc

This template returns its first argument, after adding a full stop (or its second argument) if the sentence was not finished.

title: Template:Terminate sentence/doc


text: Template:Terminate sentence

title: Template:Terminate sentence


text: Template:Strongbad

title: Template:Strongbad


text:
Template:Strongbad/doc

Usage
This template is used to insert a quick and easy warning or negative notice with high visibility (because it is red) on project and discussion pages (like the following sentence). This template cannot be used in articles. In situations where color is not relevant (color blindness, screen readers, etc.), it renders exactly the same as (to which it is a CSS-styled call). This template is only for use in template documentation, guidelines, and other Wikipedia-internal purposes. It is the opposite of the template.

or, if the important text contains an equals sign:

These both render as:

 * important text

It is safest to always use the 1 syntax.

This template puts intentional and explicit  (importance, seriousness, or urgency) HTML markup around the text provided as the first parameter.

Because some people are color blind, and some use screen readers, this template should not be used in a manner in which only the color indicates the difference between the content being marked up and other content; it's simply a visual aid for those who can use it.

Parameters
See Template:Strong.

title: Template:Strongbad/doc


text: Template:Mxt

title: Template:Mxt


text: Template:Collapse

title: Template:Collapse


text:
Template:Collapse/doc

The template is used for placing collapse boxes around short discussions and bits of discussions. To fold long discussion threads, use.

This template should only be used in accordance with the refactoring talk pages guideline; it should never be used to end a discussion over the objections of other editors, except in cases of unambiguous disruptive editing.

Do not hide content in articles. This violates the WP:Manual of Style and WP:Accessibility guidelines.

Usage
Note: Collapse needs to be substed in order for the time stamp functionality to work properly.

It is definitely safest to use the named 1 and 2 parameters, because otherwise any "=" character will break the template.

For compatibility with various discussion-boxing and -closing, and discussion-wrapping templates, 1 can also be given as content or text, and 2 can also be given as title, reason, header, heading, or result.

HTML version
If you find that the template does not function properly in a particular circumstance, this is mostly likely because the wikicode table markup (, etc.) only works when it is at the beginning of a newline.

A workaround for this is the "pure HTML" (, etc.) variant of this template, , which is identical (same parameters, etc.) other than in not using wikimarkup for the layout-table code.

The parameter
The  parameter is optional. It changes the background color. Use Web color values (e.g. ).

creates:
 * Example:

The parameter
The  parameter adjusts the amount of cell padding (defaults to  ):

creates the following (expand the box to see the border padding effect):

The parameter
The  parameter allows the collapsed content to float to the left, right, or center of the page (defaults to   with  ):

creates the following:

creates the following:

creates the following:

creates the following:

creates the following:

Around header text
When used with a section of text, include the section header in the collapsed portion of text. For example, given:

Replace with:

The parameter
Simply add yes to have the box show up in expanded form with a "hide" link, instead of collapsed form with a "show" link. Other options: expand. Note: no will fold the box (default).

The parameter
In some situations you may not want the default  CSS to apply, which puts the collapse box below any left- or right-floated content within the same HTML block. In this case, you can use none, right, or left, as needed.

When content includes tables
This template frequently breaks when used around content that consists of or includes wikitables. Such content can be made collapsible by using the and  templates instead of.

If you want to collapse only the table and not other content, you can do this using wikitable parameters. See the Collapsing tables guide for help.

TemplateData
{	"description": "Creates a collapsible box that allows its content to be hidden or revealed on user's command. It is used to reduce clutter.", "params": { "1": {			"label": "Contents", "description": "Contents of the box", "type": "content", "required": true, "aliases": [ "content", "text" ]		},		"2": {			"label": "Title", "description": "Text of title bar. Defaults to \"Extended contents\".", "type": "string", "suggested": true, "aliases": [ "title", "heading", "header", "reason", "result" ],			"default": "Extended content" },		"expand": { "label": "Expanded by default?", "description": "Setting to \"yes\" (or \"y\", \"expand\", \"expanded\", \"uncollapse\", or \"uncollapsed\") will cause the box to show its contents by default. Any other value (and omitting this parameter) causes the box to be expanded by default. If not set or set to another value (e.g. \"no\") the box will be collapsed by default (its contents hidden).", "type": "string", "default": "no" },		"border": { "label": "Border width", "description": "Width of the outermost border. Accepts a number (e.g. 2) followed immediately with a CSS-compatible unit of measurement. (e.g. \"px\") Example: 2px.", "type": "string", "default": "1px" },		"bg": { "label": "Title bar's color", "description": "Color of the title bar. Can be set any valid CSS color value but please take care that text would remain black.", "type": "string", "aliases": [ "background" ],			"default": "#F0F2F5" },		"padding": { "label": "Padding", "description": "Width of the padding, the empty space between border and the contents. Accepts a number (e.g. 2) followed immediately with a CSS-compatible unit of measurement. (e.g. \"px\") Example: 2px.", "default": "8px" },		"bg1": { "label": "Outer background", "description": "Color of the space between the inner and outer border. Can be set to any valid CSS color.", "type": "string", "default": "transparent" },		"b-color": { "label": "Outer border color", "description": "Color of the outer border. Can be any valid CSS color.", "type": "string", "default": "silver" },		"width": { "label": "Collapse box width", "description": "The width of the entire collapsed box.", "type": "string", "default": "100%" },		"center": { "label": "Center-align title", "description": "If set to any value, the title will be centered.", "type": "boolean" },		"fc": { "label": "Font color", "description": "Font color for the title. Also sets the color of the [show]/[hide] link. Can be any valid CSS color", "type": "string" },		"class": { "label": "CSS class", "description": "Additional CSS class to add", "type": "string" },		"float": { "label": "CSS float", "description": "CSS float, one of \"left\", \"right\", \"none\", \"center\"/\"centre\", or blank.", "type": "string" },		"clear": { "label": "CSS clear", "description": "CSS clear value. The default depends on the selected float.  Usually one of \"none\", \"left\", \"right\", or \"both\"", "type": "string" },		"left": { "label": "Left-align title", "description": "Left-aligns the title. Takes precedence over center.", "type": "boolean" },		"border2": { "label": "Content border", "description": "CSS border styling to add to the content.", "type": "string", "default": "1px silver" },		"bg2": { "label": "Content background color", "description": "Background color to use for expanded content.", "type": "string", "default": "white" }	} }

Re-using at other wikis
This template depends upon having rules for the three classes (collapsible, uncollapsed, and collapsed) in the appropriate CSS files, and some related JavaScript installed. This template transcludes main other and lorem ipsum, which should also be imported at the same time.

For MediaWiki versions ≥ 1.18, this template can simply be exported and then imported into another MediaWiki installation. Some changes to the source code will need to be made in order for this template to become usable on the Main/Article (ns:0) namespace.

The toggle text can be edited at external Wiki's MediaWiki:Collapsible-expand and MediaWiki:Collapsible-collapse pages. Further information at jquery.makeCollapsible module.

title: Template:Collapse/doc


text:
Module:String2

local p = {}

p.trim = function(frame) return mw.text.trim(frame.args[1] or "") end

p.sentence = function (frame) -- is strip-marker safe, string.lower is not. frame.args[1] = frame:callParserFunction('lc', frame.args[1]) return p.ucfirst(frame) end

p.ucfirst = function (frame ) local s = mw.text.trim( frame.args[1] or "" ) local s1 = "" -- if it's a list chop off and (store as s1) everything up to the first  local lipos = mw.ustring.find(s, "" ) if lipos then s1 = mw.ustring.sub(s, 1, lipos + 3) s = mw.ustring.sub(s, lipos + 4) end -- s1 is either "" or the first part of the list markup, so we can continue -- and prepend s1 to the returned string local letterpos if mw.ustring.find(s, "^%[%[^%+%]%]") then -- this is a piped wikilink, so we capitalise the text, not the pipe local _ _, letterpos = mw.ustring.find(s, "|%W*%w") -- find the first letter after the pipe else letterpos = mw.ustring.find(s, '%w') end if letterpos then local first = mw.ustring.sub(s, 1, letterpos - 1) local letter = mw.ustring.sub(s, letterpos, letterpos) local rest = mw.ustring.sub(s, letterpos + 1) return s1 .. first .. mw.ustring.upper(letter) .. rest else return s1 .. s	end end

p.title = function (frame ) -- http://grammar.yourdictionary.com/capitalization/rules-for-capitalization-in-titles.html -- recommended by The U.S. Government Printing Office Style Manual: -- "Capitalize all words in titles of publications and documents,	-- except a, an, the, at, by, for, in, of, on, to, up, and, as, but, or, and nor." local alwayslower = {['a'] = 1, ['an'] = 1, ['the'] = 1, ['and'] = 1, ['but'] = 1, ['or'] = 1, ['for'] = 1, ['nor'] = 1, ['on'] = 1, ['in'] = 1, ['at'] = 1, ['to'] = 1, ['from'] = 1, ['by'] = 1, ['of'] = 1, ['up'] = 1 } local res = '' local s = mw.text.trim( frame.args[1] or "" ) local words = mw.text.split( s, " ") for i, s in ipairs(words) do -- is strip-marker safe, string.lower is not. s = frame:callParserFunction('lc', s)		if i == 1 or alwayslower[s] ~= 1 then s = mw.getContentLanguage:ucfirst(s) end words[i] = s	end return table.concat(words, " ") end

-- findlast finds the last item in a list -- the first unnamed parameter is the list -- the second, optional unnamed parameter is the list separator (default = comma space) -- returns the whole list if separator not found p.findlast = function(frame) local s = mw.text.trim( frame.args[1] or "" ) local sep = frame.args[2] or "" if sep == "" then sep = ", " end local pattern = ".*" .. sep .. "(.*)"	local a, b, last = s:find(pattern) if a then return last else return s	end end

-- stripZeros finds the first number and strips leading zeros (apart from units) -- e.g "0940" -> "940"; "Year: 0023" -> "Year: 23"; "00.12" -> "0.12" p.stripZeros = function(frame) local s = mw.text.trim(frame.args[1] or "") local n = tonumber( string.match( s, "%d+" ) ) or "" s = string.gsub( s, "%d+", n, 1 ) return s end

-- nowiki ensures that a string of text is treated by the MediaWiki software as just a string -- it takes an unnamed parameter and trims whitespace, then removes any wikicode p.nowiki = function(frame) local str = mw.text.trim(frame.args[1] or "") return mw.text.nowiki(str) end

-- split splits text at boundaries specified by separator -- and returns the chunk for the index idx (starting at 1) -- #invoke:String2 |split |text |separator |index |true/false -- #invoke:String2 |split |txt=text |sep=separator |idx=index |plain=true/false -- if plain is false/no/0 then separator is treated as a Lua pattern - defaults to plain=true p.split = function(frame) local args = frame.args if not(args[1] or args.txt) then args = frame:getParent.args end local txt = args[1] or args.txt or "" if txt == "" then return nil end local sep = (args[2] or args.sep or ""):gsub('"', '')	local idx = tonumber(args[3] or args.idx) or 1	local plain = (args[4] or args.plain or "true"):sub(1,1)	plain = (plain ~= "f" and plain ~= "n" and plain ~= "0")	local splittbl = mw.text.split( txt, sep, plain )	if idx < 0 then idx = #splittbl + idx + 1 end	return splittbl[idx] end

-- val2percent scans through a string, passed as either the first unnamed parameter or |txt= -- it converts each number it finds into a percentage and returns the resultant string. p.val2percent = function(frame) local args = frame.args if not(args[1] or args.txt) then args = frame:getParent.args end local txt = mw.text.trim(args[1] or args.txt or "") if txt == "" then return nil end local function v2p (x) x = (tonumber(x) or 0) * 100 if x == math.floor(x) then x = math.floor(x) end return x .. "%"	end txt = txt:gsub("%d[%d%.]*", v2p) -- store just the string return txt end

-- one2a scans through a string, passed as either the first unnamed parameter or |txt= -- it converts each occurrence of 'one ' into either 'a ' or 'an ' and returns the resultant string. p.one2a = function(frame) local args = frame.args if not(args[1] or args.txt) then args = frame:getParent.args end local txt = mw.text.trim(args[1] or args.txt or "") if txt == "" then return nil end txt = txt:gsub(" one ", " a "):gsub("^one", "a"):gsub("One ", "A "):gsub("a ([aeiou])", "an %1"):gsub("A ([aeiou])", "An %1") return txt end

-- findpagetext returns the position of a piece of text in a page -- First positional parameter or |text is the search text -- Optional parameter |title is the page title, defaults to current page -- Optional parameter |plain is either true for plain search (default) or false for Lua pattern search -- Optional parameter |nomatch is the return value when no match is found; default is nil p._findpagetext = function(args) -- process parameters local nomatch = args.nomatch or "" if nomatch == "" then nomatch = nil end --	local text = mw.text.trim(args[1] or args.text or "") if text == "" then return nil end --	local title = args.title or "" local titleobj if title == "" then titleobj = mw.title.getCurrentTitle else titleobj = mw.title.new(title) end --	local plain = args.plain or "" if plain:sub(1, 1) == "f" then plain = false else plain = true end -- get the page content and look for 'text' - return position or nomatch local content = titleobj and titleobj:getContent return content and mw.ustring.find(content, text, 1, plain) or nomatch end p.findpagetext = function(frame) local args = frame.args local pargs = frame:getParent.args for k, v in pairs(pargs) do		args[k] = v	end if not (args[1] or args.text) then return nil end -- just the first value return (p._findpagetext(args)) end

-- returns the decoded url. Inverse of parser function -- Type is: -- QUERY decodes + to space (default) -- PATH does no extra decoding -- WIKI decodes _ to space p._urldecode = function(url, type) url = url or "" type = (type == "PATH" or type == "WIKI") and type return mw.uri.decode( url, type ) end -- p.urldecode = function(frame) return mw.uri.decode( frame.args.url, frame.args.type ) end

-- what follows was merged from Module:StringFunc

-- helper functions p._GetParameters = require('Module:GetParameters')

-- Argument list helper function, as per Module:String p._getParameters = p._GetParameters.getParameters

-- Escape Pattern helper function so that all characters are treated as plain text, as per Module:String function p._escapePattern( pattern_str) return mw.ustring.gsub( pattern_str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" ) end

-- Helper Function to interpret boolean strings, as per Module:String p._getBoolean = p._GetParameters.getBoolean

--[[ Strip

This function Strips characters from string

Usage:

Parameters source: The string to strip chars: The pattern or list of characters to strip from string, replaced with '' plain: A flag indicating that the chars should be understood as plain text. defaults to true.

Leading and trailing whitespace is also automatically stripped from the string. ]] function p.strip( frame ) local new_args = p._getParameters( frame.args, {'source', 'chars', 'plain'} ) local source_str = new_args['source'] or '' local chars = new_args['chars'] or '' or 'characters' source_str = mw.text.trim(source_str) if source_str ==  or chars ==  then return source_str end local l_plain = p._getBoolean( new_args['plain'] or true ) if l_plain then chars = p._escapePattern( chars ) end local result result = mw.ustring.gsub(source_str, "["..chars.."]", '') return result end

--[[ Match any Returns the index of the first given pattern to match the input. Patterns must be consecutively numbered. Returns the empty string if nothing matches for use in

Usage: returns '2'.

Parameters: source: the string to search plain: A flag indicating that the patterns should be understood as plain text. defaults to true. 1, 2, 3, ...: the patterns to search for ]] function p.matchAny(frame) local source_str = frame.args['source'] or error('The source parameter is mandatory.') local l_plain = p._getBoolean( frame.args['plain'] or true ) for i = 1, math.huge do		local pattern = frame.args[i] if not pattern then return '' end if mw.ustring.find(source_str, pattern, 1, l_plain) then return tostring(i) end end end

--[[--< H Y P H E N _ T O _ D A S H >--

Converts a hyphen to a dash under certain conditions. The hyphen must separate like items; unlike items are returned unmodified. These forms are modified: letter - letter (A - B)	digit - digit (4-5) digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5) letterdigit - letterdigit (A1-A5) (an optional separator between letter and		digit is supported – a.1-a.5 or a-1-a-5) digitletter - digitletter (5a - 5d) (an optional separator between letter and		digit is supported – 5.a-5.d or 5-a-5-d)

any other forms are returned unmodified.

str may be a comma- or semicolon-separated list

]] function p.hyphen_to_dash( str, spacing ) if (str == nil or str == '') then return str end

local accept

str = mw.text.decode(str, true )											-- replace html entities with their characters; semicolon mucks up the text.split

local out = {} local list = mw.text.split (str, '%s*[,;]%s*')								-- split str at comma or semicolon separators if there are any

for _, item in ipairs (list) do												-- for each item in the list item = mw.text.trim(item)												-- trim whitespace item, accept = item:gsub ('^%(%((.+)%)%)$', '%1') if accept == 0 and mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then	-- if a hyphenated range or has endash or emdash separators if item:match ('^%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+$') or			-- letterdigit hyphen letterdigit (optional separator between letter and digit) item:match ('^%d+[%.%-]?%a+%s*%-%s*%d+[%.%-]?%a+$') or			-- digitletter hyphen digitletter (optional separator between digit and letter) item:match ('^%d+[%.%-]%d+%s*%-%s*%d+[%.%-]%d+$') or			-- digit separator digit hyphen digit separator digit item:match ('^%d+%s*%-%s*%d+$') or								-- digit hyphen digit item:match ('^%a+%s*%-%s*%a+$') then							-- letter hyphen letter item = item:gsub ('(%w*[%.%-]?%w+)%s*%-%s*(%w*[%.%-]?%w+)', '%1–%2')	-- replace hyphen, remove extraneous space characters else item = mw.ustring.gsub (item, '%s*[–—]%s*', '–')				-- for endash or emdash separated ranges, replace em with en, remove extraneous whitespace end end table.insert (out, item)												-- add the (possibly modified) item to the output table end

local temp_str = table.concat (out, ',' .. spacing)							-- concatenate the output table into a comma separated string temp_str, accept = temp_str:gsub ('^%(%((.+)%)%)$', '%1')					-- remove accept-this-as-written markup when it wraps all of concatenated out if accept ~= 0 then temp_str = str:gsub ('^%(%((.+)%)%)$', '%1')							-- when global markup removed, return original str; do it this way to suppress boolean second return value end return temp_str end

function p.hyphen2dash( frame ) local str = frame.args[1] or '' local spacing = frame.args[2] or ' ' -- space is part of the standard separator for normal spacing (but in conjunction with templates r/rp/ran we may need a narrower spacing

return p.hyphen_to_dash(str, spacing) end

-- Similar to Module:String function p.startswith(frame) return (frame.args[1]:sub(1, frame.args[2]:len) == frame.args[2]) and 'yes' or '' end

return p

title: Module:String2


text:
Module:String2/doc

The module String2 contains a number of string manipulation functions that are much less commonly used than those in Module:String. Because Module:String is cascade-protected (some of its functions are used on the Main Page), it cannot be edited or maintained by template editors, only by admins. While it is true that string-handling functions rarely need maintenance, it is useful to allow that by template editors where possible, so this module may be used by template editors to develop novel functionality.

The module contains three case-related calls that convert strings to first letter uppercase, sentence case or title case and two calls that are useful for working with substrings. There are other utility calls that strip leading zeros from padded numbers and transform text so that it is not interpreted as wikitext, and several other calls that solve specific problems for template developers such as finding the position of a piece of text on a given page.

The functions are designed with the possibility of working with text returned from Wikidata in mind. However, a call to Wikidata may return empty, so the functions should generally fail gracefully if supplied with a missing or blank input parameter, rather than throwing an error.

trim
The trim function simply trims whitespace characters from the start and end of the string.

title
The title function capitalises the first letter of each word in the text, apart from a number of short words recommended by The U.S. Government Printing Office Style Manual: a, an, the, at, by, for, in, of, on, to, up, and, as, but, or, and nor.

sentence
The sentence function finds the first letter and capitalises it, then renders the rest of the text in lower case. It works properly with text containing wiki markup. Compare  →  with   → Action game. Piped wiki-links are handled as well: So are lists:
 * →

ucfirst
The ucfirst function is similar to sentence; it renders the first alphabetical character in upper case, but leaves the capitalisation of the rest of the text unaltered. This is useful if the text contains proper nouns, but it will not regularise sentences that are ALLCAPS, for example. It also works with text containing piped wiki-links and with html lists.

findlast

 * Function findlast finds the last item in a list.
 * The first unnamed parameter is the list. The list is trimmed of leading and trailing whitespace
 * The second, optional unnamed parameter is the list separator (default = comma space). The separator is not trimmed of leading and trailing whitespace (so that leading or trailing spaces can be used).
 * It returns the whole list if the separator is not found.

One potential issue is that using Lua special pattern characters as the separator will probably cause problems.

split
The split function splits text at boundaries specified by separator and returns the chunk for the index idx (starting at 1). It can use positional parameters or named parameters (but these should not be mixed): Any double quotes (") in the separator parameter are stripped out, which allows spaces and wikitext like  to be passed. Use   for the pipe character.

If the optional plain parameter is set to  then separator is treated as a Lua pattern. The default is plain=true, i.e. normal text matching.

The index parameter is optional; it defaults to the first chunk of text.

The Template:Stringsplit is a convenience wrapper for the split function.

stripZeros
The stripZeros functions finds the first number in a string of text and strips leading zeros, but retains a zero which is followed by a decimal point. For example: "0940" → "940"; "Year: 0023" → "Year: 23"; "00.12" → "0.12"

nowiki
The nowiki function ensures that a string of text is treated by the MediaWiki software as just a string, not code. It trims leading and trailing whitespace.

val2percent
The val2percent functions scans through a string, passed as either the first unnamed parameter or |txt=, and converts each number it finds into a percentage, then returns the resulting string.

one2a
The one2a function scans through a string, passed as either the first unnamed parameter or |txt=, and converts each occurrence of 'one ' into either 'a ' or 'an ', then returns the resultant string.

The Template:One2a is a convenience wrapper for the one2a function.

findpagetext
The findpagetext function returns the position of a piece of text in the wikitext source of a page. It takes up to four parameters:
 * First positional parameter or |text is the text to be searched for.
 * Optional parameter |title is the page title, defaults to the current page.
 * Optional parameter |plain is either true for a plain search (default), or false for a Lua pattern search.
 * Optional parameter |nomatch is the value returned when no match is found; default is nothing.

 * Examples
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}
 * → {{#invoke:String2 |findpagetext |text=%{%{coord |title=Boston Bridge |plain=f |nomatch=not found}}

The search is case-sensitive, so Lua pattern matching is needed to find  or. The last example finds  and. The penultimate example finds a wiki-link.

The Template:Findpagetext is a convenience wrapper for this function.

strip
The strip function strips the first positional parameter of the characters or pattern supplied in the second positional parameter.

matchAny
The matchAny function returns the index of the first positional parameter to match the source parameter. If the plain parameter is set to false (default true) then the search strings are Lua patterns. This can usefully be put in a switch statement to pick a switch case based on which pattern a string matches. Returns the empty string if nothing matches, for use in.

returns 2.

hyphen2dash
Extracted hyphen_to_dash function from Module:Citation/CS1.

Converts a hyphen to a dash under certain conditions. The hyphen must separate like items; unlike items are returned unmodified. These forms are modified:
 * letter - letter (A - B)
 * digit - digit (4-5)
 * digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5)
 * letterdigit - letterdigit (A1-A5) (an optional separator between letter and digit is supported – a.1-a.5 or a-1-a-5)
 * digitletter - digitletter (5a - 5d) (an optional separator between letter and digit is supported – 5.a-5.d or 5-a-5-d)

Any other forms are returned unmodified.

The input string may be a comma- or semicolon-separated list. Semicolons are converted to commas.

returns.

returns.

Accept-this-as-written markup is supported, e.g.  returns.

By default, a normal space is inserted after the separating comma in lists. An optional second parameter allows to change this to a different character (i.e. a thin space or hair space).

startswith
A startswith function similar to. Both parameters are required, although they can be blank. Leading and trailing whitespace is counted, use named parameters to avoid this if required. Outputs "yes" for true and blank for false so may be passed directly to #if.

Usage

 * - Capitalizes the first character and shifts the rest to lowercase
 * Although similar to magic words'  function, this call works even with piped wiki-links because it searches beyond leading brackets and other non-alphanumeric characters.
 * It now also recognises when it has an html list passed to it and capitalises the first alphabetic letter beyond the list item markup and any piped links that may be there.
 * - Capitalizes the first alphabetic character and leaves the rest unaltered
 * Works with piped wiki-links and html lists
 * - Capitalizes all words, except for,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  ,  , and.
 * - Removes leading padding zeros from the first number it finds in the string
 * - Renders the string as plain text without wikicode

Parameters
These functions take one unnamed parameter comprising (or invoking as a string) the text to be manipulated:
 * title
 * sentence
 * ucfirst

String split
Template:String split is a convenience wrapper for the split function. Modules may return strings with | as separators like this:  → Lua patterns can allow splitting at classes of characters such as punctuation: Or split on anything that isn't a letter (no is treated as false): Named parameters force the trimming of leading and trailing spaces in the parameters and are generally clearer when used:

One2a
Template:One2a is a convenience wrapper for the one2a function.

Capitalisation is kept. Aimed for usage with Convert.

 * → 1 ft
 * → 2.54 cm
 * → 2.54 cm

title: Module:String2/doc


text:
Module:Cs1 documentation support

require('strict'); local getArgs = require ('Module:Arguments').getArgs;

local cfg = mw.loadData ('Module:Citation/CS1/Configuration');					-- load the configuration module local whitelist = mw.loadData ('Module:Citation/CS1/Whitelist');				-- load the whitelist module

local exclusion_lists = {														-- TODO: move these tables into a separate ~/data module and mw.loadData it	['cite book'] = { ['agency'] = true, ['air-date'] = true, ['arxiv'] = true, ['biorxiv'] = true, ['citeseerx'] = true, ['class'] = true, ['conference'] = true, ['conference-format'] = true, ['conference-url'] = true, ['degree'] = true, ['department'] = true, ['display-interviewers'] = true, ['docket'] = true, ['episode'] = true, ['interviewer#'] = true, ['interviewer-first#'] = true, ['interviewer-link#'] = true, ['interviewer-mask#'] = true, ['ismn'] = true, ['issn'] = true, ['issue'] = true, ['jfm'] = true, ['journal'] = true, ['jstor'] = true, ['mailinglist'] = true, ['message-id'] = true, ['minutes'] = true, ['MR'] = true, ['network'] = true, ['number'] = true, ['RFC'] = true, ['script-journal'] = true, ['season'] = true, ['section'] = true, ['sections'] = true, ['series-link'] = true, ['series-number'] = true, ['series-separator'] = true, ['sheet'] = true, ['sheets'] = true, ['SSRN'] = true, ['station'] = true, ['time'] = true, ['time-caption'] = true, ['trans-article'] = true, ['trans-journal'] = true, ['transcript'] = true, ['transcript-format'] = true, ['transcript-url'] = true, ['ZBL'] = true, },	['cite journal'] = { ['agency'] = true, ['air-date'] = true, ['book-title'] = true, ['chapter'] = true, ['chapter-format'] = true, ['chapter-url'] = true, ['chapter-url-access'] = true, ['class'] = true, ['conference'] = true, ['conference-format'] = true, ['conference-url'] = true, ['contribution'] = true, ['contributor#'] = true, ['contributor-first#'] = true, ['contributor-link#'] = true, ['contributor-mask#'] = true, ['degree'] = true, ['department'] = true, ['display-interviewers'] = true, ['docket'] = true, ['edition'] = true, ['editor#'] = true, ['editor-first#'] = true, ['editor-link#'] = true, ['editor-mask#'] = true, ['editors'] = true, ['encyclopedia'] = true, ['episode'] = true, ['ignore-isbn-error'] = true, ['interviewer#'] = true, ['interviewer-first#'] = true, ['interviewer-link#'] = true, ['interviewer-mask#'] = true, ['isbn'] = true, ['ismn'] = true, ['LCCN'] = true, ['mailinglist'] = true, ['message-id'] = true, ['minutes'] = true, ['network'] = true, ['script-chapter'] = true, ['season'] = true, ['section'] = true, ['sections'] = true, ['series-link'] = true, ['series-number'] = true, ['series-separator'] = true, ['sheet'] = true, ['sheets'] = true, ['station'] = true, ['time'] = true, ['time-caption'] = true, ['trans-article'] = true, ['transcript'] = true, ['transcript-format'] = true, ['transcript-url'] = true, },	}

--[[-< A D D _ T O _ L I S T >-

adds code/name pair to code_list and name/code pair to name_list; code/name pairs in override_list replace those taken from the MediaWiki list; these are marked with a superscripted dagger.

 * script- = lang codes always use override names so dagger is omitted

]]

local function add_to_list (code_list, name_list, override_list, code, name, dagger) if false == dagger then dagger = '';															-- no dagger for |script- = codes and names else dagger = '†';												-- dagger for all other lists using override end

if override_list[code] then													-- look in the override table for this code code_list[code] = override_list[code] .. dagger;						-- use the name from the override table; mark with dagger name_list[override_list[code]] = code .. dagger; else code_list[code] = name;													-- use the MediaWiki name and code name_list[name] = code; end end

--[[-< L I S T _ F O R M A T >-

formats key/value pair into a string for rendering ['k'] = 'v'	→ k: v

]]

local function list_format (result, list) for k, v in pairs (list)	do table.insert (result, k .. ': ' .. v); end end

--[[-< L A N G _ L I S T E R >-

Module entry point

Crude documentation tool that returns one of several lists of language codes and names.

Used in Template:Citation Style documentation/language/doc

{{#invoke:cs1 documentation support|lang_lister|list= |lang= ', name);		-- same as {{para| }}	end

return string.format ('%s', args.id or '', name);			-- because {{csdoc}} bolds param names end

--[[--< A L I A S _ N A M E S _ G E T >

returns list of aliases for metaparameter returns empty string when there are no aliases returns empty string when name not found in alias_src{} or id_src{}; access icon parameters have no aliases so ignored

metaparameter is the key in Module:Citation/CS1 aliases{} table or id_handlers{} table.

Some lists of aliases might be better served when a particular alias is identified as the canonical alias for a particular use case. If, for example, Perodical lists: 'journal', 'magazine', 'newspaper', 'periodical', 'website', 'work' that order works fine for {{cite journal}} documentation but doesn't work so well for {{cite magazine}}, {{cite news}}, or {{cite web}}. So, for using this function to document {{cite magazine}} the returned value should be the aliases that are not best suited for that template so we can specify magazine in the override (frame.args[2]) to be the canonical parameter so it won't be listed with the rest of the aliases (normal canonical journal will be)

must exist in the alias list except: when value is 'all', returns the canonical parameter plus all of the aliases

output format is controlled by |format= plain - renders in plain text in a tag; may have id attribute para - renders as it would in {{para| }} when not specified, refurns the default bold format used for {{csdoc}}

{{#invoke:cs1 documentation support|alias_name_get| | |format=[plain|para]}}

]]

local function alias_names_get (frame) local alias_src = cfg.aliases;												-- get master list of aliases local id_src = cfg.id_handlers;												-- get master list of identifiers local args = getArgs (frame); local meta = args[1]; local override = args[2];

local out = {}; local source;																-- selected parameter or id aliases list local aliases;

source = alias_src[meta] or (id_src[meta] and id_src[meta].parameters); if not source then if meta:match ('%u+access') then return 'no' == args.none and '' or 'none';							-- custom access parameters don't have aliases else return '';															-- no such meta end elseif not source[2] then													-- id_source[meta] is always a table; if no second member, no aliases return 'no' == args.none and '' or 'none'; end if not override then aliases = source;														-- normal skip-canonical param case else local flag = 'all' == override and true or nil;							-- so that we know that parameter is a valid alias; spoof when override == 'all' aliases = {[1] = ''};													-- spoof to push alias_src[meta][1] and id_src[meta][1] into aliases[2] for _, v in ipairs (source) do											-- here when override is set; spin through the aliases to make sure override matches alias in table if v ~= override then table.insert (aliases, v);										-- add all but overridden param to the the aliases list for this use case else flag = true;													-- set the flag so we know that is a valid alias end end if not flag then aliases = {}														-- unset the table as error indicator end end

if 'table' == type (aliases) then											-- table only when there are aliases for i, alias in ipairs (aliases) do			if 1 ~= i then														-- aliases[1] is the canonical name; don't include it				if 'plain' == args.format then									-- format and return the output table.insert (out, alias);									-- plain text elseif 'para' == args.format then table.insert (out, string.format (' ', alias));	-- same as {{para| }} else table.insert (out, string.format ("%s", alias));		-- because csdoc bolds param names end end end return table.concat (out, ', ');										-- make pretty list and quit end

return 'no' == args.none and '' or 'none';									-- no metaparameter with that name or no aliases end

--[[--< I S _ B O O K _ C I T E _ T E M P L A T E >

fetch the title of the current page; if it is a preprint template, return true; empty string else

]]

local book_cite_templates = { ['citation'] = true, ['cite book'] = true, }

local function is_book_cite_template local title = mw.title.getCurrentTitle.rootText;							-- get title of current page without namespace and without sub-pages; from Template:Cite book/new -> Cite book title = title and title:lower or ''; return book_cite_templates[title] or ''; end

--[[--< I S _ L I M I T E D _ P A R A M _ T E M P L A T E >

fetch the title of the current page; if it is a preprint template, return true; empty string else

]]

local limited_param_templates = {												-- if ever there is a need to fetch info from ~/Whitelist then ['cite arxiv'] = true,														-- this list could also be fetched from there ['cite biorxiv'] = true, ['citeseerx'] = true, ['ssrn'] = true, }

local function is_limited_param_template local title = mw.title.getCurrentTitle.rootText;							-- get title of current page without namespace and without sub-pages; from Template:Cite book/new -> Cite book title = title and title:lower or ''; return limited_param_templates[title] or ''; end

--[[--< H E A D E R _ M A K E >

makes a section header from  and ; defaults to 2; cannot be less than 2

]]

local function _header_make (args) if not args[1] then return '';																-- no header text end local level = args[2] and tonumber (args[2]) or 2; level = string.rep ('=', level); return level .. args[1] .. level; end

--[[--< H E A D E R _ M A K E >

Entry from an {{#invoke:}} makes a section header from  and ; defaults to 2; cannot be less than 2

]]

local function header_make (frame) local args = getArgs (frame); return _header_make (args); end

--[[--< I D _ L I M I T S _ G E T >

return the limit values for named identifier parameters that have  limits (pmc, pmid, ssrn, s2cid, oclc, osti, rfc); the return value used in template documentation and error message help-text

{{#invoke:Cs1 documentation support|id_limits_get|}}

]]

local function id_limits_get (frame) local args = getArgs (frame); local handlers = cfg.id_handlers;											-- get id_handlers {} table from ~/Configuration

return args[1] and handlers[args[1]:upper].id_limit or (' No limit defined for identifier: ' .. (args[1] or ' ') .. ' '); end

----< C A T _ L I N K _ M A K E >

local function cat_link_make (cat) return table.concat ({'Category:', cat, ''}); end

--[[--< S C R I P T _ C A T _ L I S T E R >

utility function to get script-language categories

]]

local lang_list_t = mw.language.fetchLanguageNames ('en', 'all'); local function script_cat_lister (script_lang_codes_t, lang_code_remap_t, cats_list_t) for _, lang_code in ipairs (script_lang_codes_t) do		local lang_name = lang_code_remap_t[lang_code] or lang_list_t[lang_code];	-- use remap table to get Bengali instead of Bangla and the like; else use standard MediaWiki names local cat = 'CS1 uses ' .. lang_name .. '-language script (' .. lang_code .. ')';	-- build a category name cats_list_t[cat] = 1;													-- and save it	end end

--[[--< C S 1 _ C A T _ L I S T E R >--

This is a crude tool that reads the category names from Module:Citation/CS1/Configuration, makes links of them, and then lists them in sorted lists. A couple of parameters control the rendering of the output: |select=	-- (required) takes one of three values: error, maint, prop |sandbox=	-- takes one value: no	|hdr-lvl=	-- base header level (number of == that make a header); default:2 min:2

This tool will automatically attempt to load a sandbox version of ~/Configuration if one exists. Setting |sandbox=no will defeat this.

{{#invoke:cs1 documentation support|cat_lister|select=|sandbox=}}

]]

local function cat_lister (frame) local args = getArgs (frame);

local list_live_cats = {};													-- list of live categories local list_sbox_cats = {};													-- list of sandbox categories local live_sbox_out = {}													-- list of categories that are common to live and sandbox modules local live_not_in_sbox_out = {}												-- list of categories in live but not sandbox local sbox_not_in_live_out = {}												-- list of categories in sandbox but not live local out = {};																-- final output assembled here local sandbox;																-- boolean; true: evaluate the sandbox module local hdr_lvl;																-- local sb_cfg; local sandbox, sb_cfg = pcall (mw.loadData, 'Module:Citation/CS1/Configuration/sandbox');	-- get sandbox configuration

local cat;

local select = args.select; if 'no' == args.sandbox then												-- list sandbox? sandbox = false;														-- no, live only end if hdr_lvl then																-- if set and if tonumber (hdr_lvl) then												-- can be converted to number if 2 > tonumber (hdr_lvl) then										-- min is 2 hdr_lvl = 2;													-- so set to min end else																	-- can't be converted hdr_lvl = 2;														-- so default to min end else hdr_lvl = 2;															-- not set so default to min end

if 'error' == select or 'maint' == select then								-- error and main categorys handling different from poperties cats for _, t in pairs (cfg.error_conditions) do								-- get the live module's categories if ('error' == select and t.message) or ('maint' == select and not t.message) then cat = t.category:gsub ('|(.*)$', '');							-- strip sort key if any list_live_cats[cat] = 1;										-- add to the list end end if sandbox then															-- if ~/sandbox module exists and |sandbox= not set to 'no' for _, t in pairs (sb_cfg.error_conditions) do						-- get the sandbox module's categories if ('error' == select and t.message) or ('maint' == select and not t.message) then cat = t.category:gsub ('|(.*)$', '');						-- strip sort key if any list_sbox_cats[cat] = 1;									-- add to the list end end end elseif 'prop' == select then												-- prop cats for _, cat in pairs (cfg.prop_cats) do									-- get the live module's categories cat = cat:gsub ('|(.*)$', '');										-- strip sort key if any list_live_cats[cat] = 1;											-- add to the list end

script_cat_lister (cfg.script_lang_codes, cfg.lang_code_remap, list_live_cats);	-- get live module's foriegn language script cats

if sandbox then															-- if ~/sandbox module exists and |sandbox= not set to 'no' for _, cat in pairs (sb_cfg.prop_cats) do							-- get the sandbox module's categories cat = cat:gsub ('|(.*)$', '');									-- strip sort key if any list_sbox_cats[cat] = 1;										-- add to the list end

script_cat_lister (sb_cfg.script_lang_codes, sb_cfg.lang_code_remap, list_sbox_cats);	-- get sandbox module's foriegn language script cats end else return ' error: unknown selector: ' .. select .. ' '	end

for k, _ in pairs (list_live_cats) do										-- separate live/sbox common cats from cats not in sbox if not list_sbox_cats[k] and sandbox then table.insert (live_not_in_sbox_out, cat_link_make (k));				-- in live but not in sbox else table.insert (live_sbox_out, cat_link_make (k));					-- in both live and sbox end end

for k, _ in pairs (list_sbox_cats) do										-- separate sbox/live common cats from cats not in live if not list_live_cats[k] then table.insert (sbox_not_in_live_out, cat_link_make (k));				-- in sbox but not in live end end

local function comp (a, b)													-- local function for case-agnostic category name sorting return a:lower < b:lower; end

local header;																-- initialize section header with name of selected category list if 'error' == select then header = 'error'; elseif 'maint' == select then header = 'maintenance'; else header = 'properties'; end header = table.concat ({													-- build the main header		'Live ',																-- always include this		((sandbox and 'and sandbox ') or ''),									-- if sandbox evaluated, mention that		header,																	-- add the list name		' categories (',														-- finish the name and add #live_sbox_out,															-- count of categories listed ')'																		-- close	})

local templatestyles = frame:extensionTag{ name = 'templatestyles', args = { src = "Div col/styles.css" } }

header = table.concat ({													-- make a useable header		_header_make ({header, hdr_lvl}),		'\n' .. templatestyles .. ' '	-- opening for columns		});

table.sort (live_sbox_out, comp);											-- sort case agnostic acsending table.insert (live_sbox_out, 1, header);									-- insert the header at the top table.insert (out, table.concat (live_sbox_out, '\n*'));					-- make a big string of unordered list markup table.insert (out, ' \n');												-- close the and add new line so the next header works

if 0 ~= #live_not_in_sbox_out then											-- when there is something in the table header = table.concat ({												-- build header for subsection			'In live but not in sandbox (', #live_not_in_sbox_out, ')'			});		header = table.concat ({												-- make a useable header			_header_make ({header, hdr_lvl+1}),			'\n' .. templatestyles .. ' '			}); table.sort (live_not_in_sbox_out, comp); table.insert (live_not_in_sbox_out, 1, header); table.insert (out, table.concat (live_not_in_sbox_out, '\n*')); table.insert (out, ' \n'); end if 0 ~= #sbox_not_in_live_out then											-- when there is something in the table header = table.concat ({												-- build header for subsection			'In sandbox but not in live (', #sbox_not_in_live_out, ')'			});		header = table.concat ({												-- make a useable header			_header_make ({header, hdr_lvl+1}),			'\n' .. templatestyles .. ' '			}); table.sort (sbox_not_in_live_out, comp); table.insert (sbox_not_in_live_out, 1, header); table.insert (out, table.concat (sbox_not_in_live_out, '\n*')); table.insert (out, ' \n'); end

return table.concat (out);													-- concat into a huge string and done end

--[=[--< H E L P _ T E X T _ C A T S >--

To create category links at the bottom of each error help text section and on the individual error category pages; fetches category names from ~/Configuration; replaces this: {{#ifeq:{{FULLPAGENAME}}|Category:CS1 errors: bioRxiv|Category:CS1 errors: bioRxiv|Category:CS1 errors: bioRxiv}} with this: {{#invoke:Cs1 documentation support|help_text_cats|err_bad_biorxiv}} where {{{1}}} is the error_conditions key from Module:Citation/CS1/Configuration

add |pages=yes to append the number of pages in the category

]=]

local function help_text_cats (frame) local args_t = getArgs (frame); local error_conditions_t = cfg.error_conditions;							-- get the table of error conditions local replacements_t = {};													-- table to hold replacement parameters for $1 etc placeholders in category names for k, v in pairs (args_t) do												-- look for |$1= parameters if 'string' == type (k) and k:match ('^$%d+$') then						-- if found replacements_t[k] = v;												-- save key and value end end

if args_t[1] and error_conditions_t[args_t[1]] then							-- must have error_condition key and it must exist local error_cat = error_conditions_t[args_t[1]].category;				-- get error category from cs1|2 configuration if error_cat:match ('$%d') then											-- look for placeholders in  error_cat = error_cat:gsub ('$%d', replacements_t)					-- replace place holders with matching value from replacements_t end local title_obj = mw.title.getCurrentTitle;							-- get a title object for the currently displayed page local name_space = title_obj.nsText; if ('Category' == name_space) and (error_cat == title_obj.text) then	-- if this is the category page for the error message return table.concat ({'Category:', error_cat});						-- no link; just category name else																	-- here when currently displayed page is other than the error message category local pages = '';													-- default empty strin for concatenation if 'yes' == args_t.pages then										-- if we should display category page count: TODO: do we need to keep this? pages = mw.site.stats.pagesInCategory (error_cat, 'all');		-- get category page count pages = table.concat ({' (', mw.language.getContentLanguage:formatNum (pages), ' page', (1 == pages) and ')' or 's)'});	-- make renderable text			end			return table.concat ({'Category:', error_cat, '', pages});		-- link to category with or without page count		end	else		return ' unknown error_conditions key: ' .. (args_t[1] or 'key missing') .. ' ';	end end

--[[--< H E L P _ T E X T _ E R R O R _ M E S S A G E >

to render help text example error messages {{#invoke:Cs1 documentation support|help_text_error_messages|err_bad_biorxiv}}

assign a single underscore to any of the |$n= parameters to insert an empty string in the error message: {{#invoke:Cs1 documentation support|help_text_error_messages|err_bad_issn|$1=_}} -> Check |issn= value {{#invoke:Cs1 documentation support|help_text_error_messages|err_bad_issn|$1=e}} -> Check |eissn= value

error message is rendered at 120% font size; to specify another font size use |size=; must include unit specifier (%, em, etc)

]]

local function help_text_error_messages (frame) local args_t = getArgs (frame); local error_conditions = mw.loadData ('Module:Citation/CS1/Configuration').error_conditions; --	local span_o = ' '; local span_o = ''; local span_c = ' ';

local message; local out = {};																-- output goes here if args_t[1] and error_conditions[args_t[1]] then								-- must have error_condition key and it must exist message = error_conditions[args_t[1]].message; local i=1; local count; local rep; repeat rep = '$'..i			args_t[rep] = args_t[rep] and args_t[rep]:gsub ('^%s*_%s*$', '') or nil;	-- replace empty string marker with actual empty string message, count = message:gsub (rep, args_t[rep] or rep) i = i + 1; until (0 == count);

table.insert (out, span_o); table.insert (out, message); table.insert (out, span_c); else return ' unknown error_conditions key: ' .. (args_t[1] or 'key missing') .. ' ';	end local out_str = table.concat (out); return table.concat ({frame:extensionTag ('templatestyles', '', {src='Module:Citation/CS1/styles.css'}), out_str}); end

--[[--< T E M P L A T E S _ T >

This table is a k/v table of sequence tables. The keys in this table are collapsed lowercase form of the cs1|2 template names ({{ROOTPAGENAME}}): Template:Cite AV media -> citeavmedia Each subsequence table holds: [1] documentation page where the TemplateData json is stored ({{cite book}} is the oddball) [2] key to 'preprint_arguments' and unique_arguments' tables in Module:Citation/CS1/Whitelist; these keys dictate which of the basic or limited arguments and numbered arguments tables will be used to validate the content of the TemplateData

]]

local templates_t = { citearxiv = {'Template:Cite_arXiv/doc', 'arxiv'},							-- preprint arguments citeavmedia = {'Template:Cite AV media/doc', 'audio-visual'},				-- unique arguments citeavmedianotes = {'Template:Cite AV media notes/doc'},					-- no template data citebiorxiv = {'Template:Cite bioRxiv/doc', 'biorxiv'},						-- preprint arguments citebook = {'Template:Cite book/TemplateData'}, citeciteseerx = {'Template:Cite citeseerx/doc', 'citeseerx'},				-- no template data; preprint uses limited arguments citeconference = {'Template:Cite conference/doc', 'conference'},			-- unique arguments citeencyclopedia = {'Template:Cite encyclopedia/doc'}, citeepisode = {'Template:Cite episode/doc', 'episode'},						-- unique arguments citeinterview = {'Template:Cite interview/doc'}, citejournal = {'Template:Cite journal/doc'}, citemagazine = {'Template:Cite magazine/doc'}, citemailinglist = {'Template:Cite mailing list/doc', 'mailinglist'},		-- unique arguments			-- no template data citemap = {'Template:Cite map/TemplateData', 'map'},						-- unique arguments citenews = {'Template:Cite news/doc'}, citenewsgroup = {'Template:Cite newsgroup/doc', 'newsgroup'},				-- unique arguments citepodcast = {'Template:Cite podcast/doc'}, citepressrelease = {'Template:Cite press release/doc'}, citereport = {'Template:Cite report/doc', 'report'},						-- unique arguments citeserial = {'Template:Cite serial/doc', 'serial'},						-- unique arguments			-- no template data citesign = {'Template:Cite sign/doc'}, citespeech = {'Template:Cite speech/doc', 'speech'},						-- unique arguments			-- no template data citessrn = {'Template:Cite ssrn/doc', 'ssrn'},								-- preprint arguments		-- no template data citetechreport = {'Template:Cite techreport/doc'}, citethesis = {'Template:Cite thesis/doc', 'thesis'},						-- unique arguments citeweb = {'Template:Cite web/doc'}, citation = {'Template:Citation/doc'}, }

--[[--< N O _ P A G E _ T E M P L A T E S _ T >

]]

local no_page_templates_t = {};

--[[--< I D E N T I F I E R _ A L I A S E S _ T >--

a table of the identifier aliases

]]

local identifier_aliases_t = {} for identifier, handler in pairs (cfg.id_handlers) do							-- for each identifier local aliases_t = {};														-- create a table for _, alias in ipairs (handler.parameters) do								-- get the alaises aliases_t[alias] = true;												-- and add them to the table in a form that mimics the whitelist tables end identifier_aliases_t[identifier:lower] = aliases_t;						-- add new table to the identifier aliases table; use lowercase identifier base name for the key end

--[[--< T E M P L A T E _ D A T A _ J S O N _ G E T >--

get template doc page content and extract the content of the TemplateData tags (case insensitive)

is the canonical name of the template doc page (with namespace) that holds the template data; usually Template:Cite xxx/doc (except Template:Cite book/TemplateData)

]]

local function template_data_json_get (template) local json = mw.title.new (template):getContent or ;					-- get the content of the article or ; new pages edited w/ve do not have 'content' until saved; ve does not preview; phab:T221625 json = json:match ('<[Tt]emplate[Dd]ata>(.-)');		-- remove everything exept the content of the TemplatData tags return json and mw.text.jsonDecode (json);									-- decode the json string and return as a table; nil if not found end

--[[--< V A L I D A T E _ U N I Q U E _ P A R A M >

looks for (can be the canonical parameter name or can be an alias) in whitelist.basic_arguments{} and if necessary in whitelist.numbered_arguments{}. When found, returns true; nil else

is the parameter's name as listed in the TemplateData

]]

local function validate_basic_param (param) if true == whitelist.basic_arguments[param] or true == whitelist.numbered_arguments[param] then return true; end end

--[[--< V A L I D A T E _ P R E P R I N T _ P A R A M >

looks for (can be the canonical parameter name or can be an alias) in whitelist.preprint_arguments{} or whitelist.limited_basic_arguments{} or whitelist.limited_numbered_arguments{}. When found, returns true; nil else

is the parameter's name as listed in the TemplateData is key neccessary to look in the appropriate subtable of whitelist.preprint_arguments{}

]]

local function validate_preprint_param (param, key) if true == whitelist.preprint_arguments[key][param] or 		true == whitelist.limited_basic_arguments[param] or		true == whitelist.limited_numbered_arguments[param] then return true; end end

--[[--< V A L I D A T E _ U N I Q U E _ P A R A M >

looks for (can be the canonical parameter name or can be an alias) in whitelist.unique_arguments{} or whitelist.basic_arguments{} or whitelist.numbered_arguments{}. When found, returns true; nil else

is the parameter's name as listed in the TemplateData is key neccessary to look in the appropriate subtable of whitelist.unique_arguments{}

]]

local function validate_unique_param (param, key, cfg_aliases_t) if true == whitelist.unique_arguments[key][param] or true == validate_basic_param (param) then return true; end end

--[[--< V A L I D A T E _ I D _ P A R A M >

looks for in identifier_aliases_t{}. When found, returns true; nil else

is the parameter's name as listed in the TemplateData is the alias that we're looking for

]]

local function validate_id_alias (param, alias) return identifier_aliases_t[param] and identifier_aliases_t[param][alias]; end

--[[--< P A R A M _ E R R O R_ M S G >-

]]

local function param_error_msg (param) return ' is not a valid parameter'; end

--[[--< A L I A S _ E R R O R_ M S G >-

]]

local function alias_error_msg (param, alias) return ' is not a valid alias of:  '; end

--[[--< C F G _ A L I A S E S _ T _ M A K E >--

convert this from cfg.aliases{}: ['AccessDate'] = {'access-date', 'accessdate'}

to this in out_t{} ['access-date'] = 'AccessDate', ['accessdate'] = 'AccessDate',

to test if |accessdate= is an aliases of |access-date=: if out_t['access-date'] == out_t['accessdate'] ]]

local function cfg_aliasts_t_make local out_t = {}; for meta, params_t in pairs (cfg.aliases) do		if 'table' == type (params_t) then										-- metaparameters that are assigned string values do not have aliases for _, param in ipairs (params_t) do								-- for each alias param = param:gsub ('#', '');									-- get rid of enumerators out_t[param] = meta;											-- add it to the output table end end end --error (mw.dumpObject (out_t)) return out_t; end

--[[--< T E M P L A T E _ D A T A _ V A L I D A T E >--

compairs parameter names listed in a cs1|2 template's TemplateData structure (everything between  and  tag case insensitive). Returns error messages when errors found, empty string else.

{{#invoke:Cs1 documentation support|template_data_validate|{{ROOTPAGENAME}}}}

When called from a different page: {{#invoke:cs1 documentation support|template_data_validate| }} where the is the template's canonical name with or without namespace and or subpages

]]

local function template_data_validate (frame) local args_t = getArgs (frame); if not args_t[1] then return ' Error: cs1|2 template name required '; end

local template_idx = args_t[1]:lower:match ('cit[ae][^/]+');				-- args_t[1] has something if not template_idx then													-- but if not a cs1|2 template abandon with error message return ' Error: cs1|2 template name required '; else template_idx = template_idx:gsub (' ', '');								-- is what appears to be a cs1|2 template so strip spaces end

local cfg_aliases_t = cfg_aliasts_t_make ;

local template_t = templates_t[template_idx]; local out = {};

local template_doc = template_t[1]; local json_t = template_data_json_get (template_doc); if not json_t then table.insert (out, 'Error: can\'t find TemplateData'); else for param, param_t in pairs (json_t['params']) do			local param_i;														-- this will be the parameter name that gets validated if param:find ('[Ss]2[Cc][Ii][Dd]') then							-- |s2cid*= parameters are not enumerated ... param_i = param;												-- ... so don't convert the '2' to '#' else param_i = param:gsub ('%d+', '#');								-- for enumerated parameters, convert the enumerator digits to a single '#' character; all others unmolested end

local param_is_valid;												-- boolean true when param is valid; nil else if template_t[2] then												-- if template is a preprint or uses unique parameters if whitelist.preprint_arguments[template_t[2]] then				-- if a preprint template param_is_valid = validate_preprint_param (param_i, template_t[2]); if param_is_valid then if param_t['aliases'] then for _, alias in ipairs (param_t['aliases']) do								local alias_i = alias:gsub ('%d+', '#');		-- in case an enumerated parameter, convert the enumerator digits to a single '#' character if not validate_preprint_param (alias_i, template_t[2]) then	-- is 'alias' a known parameter? table.insert (out, alias_error_msg (param, alias));			-- may be known but is not supported elseif cfg_aliases_t[param_i:gsub ('#', )] ~= cfg_aliases_t[alias_i:gsub ('#', )] then	-- is 'alias' known to be an alias of 'param'? table.insert (out, alias_error_msg (param, alias)); end end end else														-- here when param not valid preprint param table.insert (out, param_error_msg (param)) end elseif whitelist.unique_arguments[template_t[2]] then			-- if a unique parameters template param_is_valid = validate_unique_param (param_i, template_t[2]); if param_is_valid then if param_t['aliases'] then for _, alias in ipairs (param_t['aliases']) do								local alias_i = alias:gsub ('%d+', '#');		-- in case an enumerated parameter, convert the enumerate digits to a single '#' character if not validate_unique_param (alias_i, template_t[2]) then	-- is 'alias' a known parameter? table.insert (out, alias_error_msg (param, alias)); elseif cfg_aliases_t[param_i:gsub ('#', )] ~= cfg_aliases_t[alias_i:gsub ('#', )] then	-- is 'alias' known to be an alias of 'param'? table.insert (out, alias_error_msg (param, alias)); end end end else														-- here when param not valid unique parameter table.insert (out, param_error_msg (param)) end else															-- should never be here if coder is doing the right thing ... table.insert (out, 'internal error: unexpected keyword in templates_t: ' .. template_t[2]); break; end else																-- here when not unique or preprint param_is_valid = validate_basic_param (param_i); if param_is_valid then if param_t['aliases'] then for _, alias in ipairs (param_t['aliases']) do							local alias_i = alias:gsub ('%d+', '#');			-- in case an enumerated parameter, convert the enumerate digits to a single '#' character if not validate_basic_param (alias_i) and not validate_id_alias (param, alias) then	-- for isbn13 (while still supported) must not mask the digits table.insert (out, alias_error_msg (param, alias)); end end end else															-- here when param not valid table.insert (out, param_error_msg (param)) end end end end

-- this emits errors when page/pages/at listed in templatedata of templates that don't support those parameters -- --	if json_t then --		if ({['citeavmedia']=true, ['citeepisode']=true, ['citemailinglist']=true, ['citenewsgroup']=true, ['citepodcast']=true, ['citeserial']=true, ['citesign']=true, ['citespeech']=true})[template_idx] then --			local insource_params_t = {};										-- build sequence of pagination params not supported by these templates --			for _, meta_param in ipairs ({'At', 'Page', 'Pages', 'QuotePage', 'QuotePages'}) do --				if 'table' == type (cfg.aliases[meta_param]) then --					for _, alias in ipairs (cfg.aliases[meta_param]) do			-- metaparameter is a sequence --						table.insert (insource_params_t, alias);				-- add the aliases from the metaparameter sequence to the table --					end --				else															-- metaparameter is plain text --					table.insert (insource_params_t, cfg.aliases[meta_param]);	-- add the alias to the table --				end --			end --		--			for _, param in ipairs (insource_params_t) do --				if json_t.params[param] then --					table.insert (out, param_error_msg (param));				-- error; this parameter not supported by this template --				end --			end --		end --	end -- end page/pages/at error detection --

if 0 ~= #out then table.sort (out); out[1] = '*' .. out[1];													-- add a splat to the first error message

--		return table.concat ({'' .. template_doc .. ' TemplateData has errors: \n', table.concat (out, '\n*'), ' '}); return table.concat ({			'Template:' .. args_t[1] .. ' uses ',			whitelist.preprint_arguments[template_t[2]] and 'preprint and limited parameter sets' or (whitelist.unique_arguments[template_t[2]] and 'unique and standard parameter sets' or 'standard parameter set'),			'; TemplateData has errors:\n',			' \n', table.concat (out, '\n*'), ' '			}); else return;																	-- no errors detected; return nothing end end

--[[--< E R R O R _ C A T _ P A G E _ T A L L Y >--

loop through Module:Citation/CS1/Configuration error_conditions {} fetching error category names. For each error category add the number of pages in the category to the tally. Render the number when done.

{{#invoke:cs1 documentation support|error_cat_page_tally}}

]]

local function error_cat_page_tally local error_conditions_t = cfg.error_conditions;							-- get the table of error conditions local tally = 0; local cat_t = {};															-- some error message share a category; save tallied cats here so we don't recount the already counted local i = 0;																-- number of categories for k, v_t in pairs (error_conditions_t) do		if k:match ('^err') then if not cat_t[v_t.category] then cat_t[v_t.category] = true; tally = tally + mw.site.stats.pagesInCategory (v_t.category, 'pages');		-- get category page count; ignore subcats and files i = i + 1; end end end

return mw.language.getContentLanguage:formatNum (tally) end

--[[--< M A I N T _ C A T _ P A G E _ T A L L Y >--

loop through Module:Citation/CS1/Configuration error_conditions {} fetching error category names. For each error category add the number of pages in the category to the tally. Render the number when done.

{{#invoke:cs1 documentation support|maint_cat_page_tally}}

Dynamic subcats of CS1 maint: DOI inactive not counted because these names come and go as time goes by.

]]

local function maint_cat_page_tally local error_conditions_t = cfg.error_conditions;							-- get the table of error conditions local tally = 0; local cat_t = {};															-- some error message share a category; save tallied cats here so we don't recount the already counted local i = 0;																-- number of categories for k, v_t in pairs (error_conditions_t) do		if not k:match ('^err') then											-- if not an error key its a maint key if not cat_t[v_t.category] then cat_t[v_t.category] = true; if 'maint_mult_names' == k or 'maint_numeric_names' == k then local special_case_translation_t = cfg.special_case_translation; for _, name in ipairs ({'AuthorList', 'ContributorList', 'EditorList', 'InterviewerList', 'TranslatorList'}) do						local cat_name = v_t.category:gsub ('$1', special_case_translation_t[name]);	-- replace $1 with translated list name tally = tally + mw.site.stats.pagesInCategory (cat_name, 'pages');		-- get category page count; ignore subcats and files i = i + 1; end else tally = tally + mw.site.stats.pagesInCategory (v_t.category, 'pages');		-- get category page count; ignore subcats and files i = i + 1; end end end end

return mw.language.getContentLanguage:formatNum (tally) end

--[[--< U N C A T E G O R I Z E D _ N A M E S P A C E _ L I S T E R >--

For use in the Help:CS1 error §Notes

Get namespace names and identifiers from MediaWiki. Make a human readable list of namespace names and identifiers that cs1|2 does not categorize.

{{#invoke:cs1 documentation support|uncategorized_namespace_lister}}

For convenience, {{#invoke:cs1 documentation support|uncategorized_namespace_lister|all= }}

returns a list of all namespace names and identifiers used on the current wiki. Any namespace with an identifier less than 1, currently Mainspace (0), Special (-1), and Media (-2), is excluded from the list.

]]

local function uncategorized_namespace_lister (frame) --TEMP DEVELOPMENT 2022-07-09 -- delete at next module update local cfg = mw.loadData ('Module:Citation/CS1/Configuration/sandbox');	-- load the SANDBOX configuration module --END TEMP DEVELOPMENT local list_t = {}; local function compare (a, b)												-- local function to sort namespaces numerically by the identifiers local a_num = tonumber (a:match ('%d+'));								-- get identifiers and convert to numbers local b_num = tonumber (b:match ('%d+')); return a_num < b_num;													-- do the comparison end for i, _ in pairs (mw.site.namespaces) do									-- for each namespace in the table if '' == frame.args.all or not frame.args.all then						-- when |all= not set, make a list of uncategorized namespaces if cfg.uncategorized_namespaces[i] then								-- if the identifier is listed in our uncategorized namespace list table.insert (list_t, table.concat ({mw.site.namespaces[i].name, ' (', i, ')'}))	-- add name and identifier to our local list end elseif 0 < i then														-- |all= : all namespace names and identifiers; ignore identifiers less than 1 table.insert (list_t, table.concat ({'*', mw.site.namespaces[i].name, ' (', i, ')'}))	-- add name and identifier as an unordered list item end end table.sort (list_t, compare);												-- ascending numerical sort by identifier

if not frame.args.all then													-- when |all= not set, format list of uncategorized namespaces and identifiers list_t[#list_t] = 'and ' .. list_t[#list_t];							-- add 'and ' to the last name/identifier pair return table.concat (list_t, ', ');										-- make a big string and done else																		-- make list of all namespaces and identifiers return table.concat (list_t, '\n');									-- make a big string and done end end

----< E X P O R T E D  F U N C T I O N S >--

return { alias_lister = alias_lister, alias_names_get = alias_names_get, canonical_param_lister = canonical_param_lister, canonical_name_get = canonical_name_get, cat_lister = cat_lister, error_cat_page_tally = error_cat_page_tally, header_make = header_make, help_text_cats = help_text_cats, help_text_error_messages = help_text_error_messages, id_limits_get = id_limits_get, is_book_cite_template = is_book_cite_template, is_limited_param_template = is_limited_param_template, lang_lister = lang_lister, maint_cat_page_tally = maint_cat_page_tally, script_lang_lister = script_lang_lister, template_data_validate = template_data_validate, uncategorized_namespace_lister = uncategorized_namespace_lister, };

title: Module:Cs1 documentation support


text:
Module:GetParameters

local p = {}

-- Helper function that populates the argument list given that user may need to use a mix of named and unnamed parameters. This is relevant because named parameters are not identical to unnamed parameters due to string trimming, and when dealing with strings we sometimes want to either preserve or remove that whitespace depending on the application. function p.getParameters( frame_args, arg_list ) local new_args = {}; local index = 1; local value; for i,arg in ipairs( arg_list ) do       value = frame_args[arg] if value == nil then value = frame_args[index]; index = index + 1; end new_args[arg] = value; end return new_args; end

-- Helper Function to interpret boolean strings function p.getBoolean( boolean_str ) local boolean_value; if type( boolean_str ) == 'string' then boolean_str = boolean_str:lower; if boolean_str == 'false' or boolean_str == 'no' or boolean_str == '0' or boolean_str == '' then boolean_value = false; else boolean_value = true; end elseif type( boolean_str ) == 'boolean' then boolean_value = boolean_str; else error( 'No boolean value found' ); end return boolean_value end

function p.defined(frame) local arg = mw.text.trim(frame.args[1]) --if arg == tostring(tonumber(arg)) then -- undesired result for '-0' --	arg = tonumber(arg) --end --if mw.ustring.find(arg, '^%s*-?[1-9][0-9]*%s*$') ~= nil or arg == '0' then --	arg = tonumber(arg) --end if mw.ustring.find(arg, '^-?[1-9][0-9]*$') ~= nil then arg = tonumber(arg) elseif arg == '0' then arg = 0 end return frame:getParent.args[arg] ~= nil end

return p

title: Module:GetParameters


text: Module:GetParameters/doc

title: Module:GetParameters/doc