Difference between revisions of "Module:Message box"
Allow passing attributes per protected edit request by User:Jackmcbarn. Also remove undocumented "hidden" parameter and format the module so it mostly fits within 80 chars.
>Mr. Stradivarius (Allow passing attributes per protected edit request by User:Jackmcbarn. Also remove undocumented "hidden" parameter and format the module so it mostly fits within 80 chars.) |
|||
Line 1: | Line 1: | ||
-- This is a meta-module for producing message box templates, including {{mbox}}, {{ambox}}, | -- This is a meta-module for producing message box templates, including | ||
-- {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}. | |||
-- Require necessary modules. | -- Require necessary modules. | ||
Line 122: | Line 122: | ||
nsVals[i] = format('"%s"', val) | nsVals[i] = format('"%s"', val) | ||
end | end | ||
error('invalid ns parameter passed to box:addCat; valid values are ' .. mw.text.listToText(nsVals, nil, ' or ')) | error( | ||
'invalid ns parameter passed to box:addCat; valid values are ' | |||
.. mw.text.listToText(nsVals, nil, ' or ') | |||
) | |||
end | end | ||
self[tname] = self[tname] or {} | self[tname] = self[tname] or {} | ||
Line 136: | Line 139: | ||
self.classes = self.classes or {} | self.classes = self.classes or {} | ||
tinsert(self.classes, class) | tinsert(self.classes, class) | ||
end | |||
function box:addAttr(attr, val) | |||
if type(attr) ~= 'string' or type(val) ~= 'string' then return end | |||
self.attrs = self.attrs or {} | |||
tinsert(self.attrs, attr) | |||
end | end | ||
Line 158: | Line 167: | ||
end | end | ||
tinsert(boxTypes, '"mbox"') | tinsert(boxTypes, '"mbox"') | ||
error(format('invalid message box type "%s"; valid types are %s', tostring(boxType), mw.text.listToText(boxTypes)), 2) | error(format( | ||
'invalid message box type "%s"; valid types are %s', | |||
tostring(boxType), | |||
mw.text.listToText(boxTypes) | |||
), 2) | |||
end | end | ||
return cfg | return cfg | ||
Line 164: | Line 177: | ||
function box:removeBlankArgs(cfg, args) | function box:removeBlankArgs(cfg, args) | ||
-- Only allow blank arguments for the parameter names listed in cfg.allowBlankParams. | -- Only allow blank arguments for the parameter names listed in | ||
-- cfg.allowBlankParams. | |||
local newArgs = {} | local newArgs = {} | ||
for k, v in pairs(args) do | for k, v in pairs(args) do | ||
Line 181: | Line 195: | ||
self.type = args.type | self.type = args.type | ||
local typeData = cfg.types[self.type] | local typeData = cfg.types[self.type] | ||
self.invalidTypeError = cfg.showInvalidTypeError and self.type and not typeData and true or false | self.invalidTypeError = cfg.showInvalidTypeError | ||
and self.type | |||
and not typeData | |||
and true | |||
or false | |||
typeData = typeData or cfg.types[cfg.default] | typeData = typeData or cfg.types[cfg.default] | ||
self.typeClass = typeData.class | self.typeClass = typeData.class | ||
Line 206: | Line 224: | ||
self.id = args.id | self.id = args.id | ||
end | end | ||
self:addClass(cfg.usePlainlinksParam and yesno(args.plainlinks or true) and 'plainlinks') | self:addClass( | ||
cfg.usePlainlinksParam and yesno(args.plainlinks or true) and 'plainlinks' | |||
) | |||
for _, class in ipairs(cfg.classes or {}) do | for _, class in ipairs(cfg.classes or {}) do | ||
self:addClass(class) | self:addClass(class) | ||
Line 212: | Line 232: | ||
if self.isSmall then | if self.isSmall then | ||
self:addClass(cfg.smallClass or 'mbox-small') | self:addClass(cfg.smallClass or 'mbox-small') | ||
end | end | ||
self:addClass(self.typeClass) | self:addClass(self.typeClass) | ||
self:addClass(args.class) | self:addClass(args.class) | ||
self.style = args.style | self.style = args.style | ||
self.attrs = args.attrs | |||
-- Set text style. | -- Set text style. | ||
self.textstyle = args.textstyle | self.textstyle = args.textstyle | ||
-- Find if we are on the template page or not. This functionality is only used if useCollapsibleTextFields is set, | -- Find if we are on the template page or not. This functionality is only | ||
-- used if useCollapsibleTextFields is set, or if both cfg.templateCategory | |||
-- and cfg.templateCategoryRequireName are set. | |||
self.useCollapsibleTextFields = cfg.useCollapsibleTextFields | self.useCollapsibleTextFields = cfg.useCollapsibleTextFields | ||
if self.useCollapsibleTextFields or cfg.templateCategory and cfg.templateCategoryRequireName then | if self.useCollapsibleTextFields | ||
or cfg.templateCategory | |||
and cfg.templateCategoryRequireName | |||
then | |||
self.name = args.name | self.name = args.name | ||
if self.name then | if self.name then | ||
local templateName = mw.ustring.match(self.name, '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$') or self.name | local templateName = mw.ustring.match( | ||
self.name, | |||
'^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$' | |||
) or self.name | |||
templateName = 'Template:' .. templateName | templateName = 'Template:' .. templateName | ||
self.templateTitle = getTitleObject(templateName) | self.templateTitle = getTitleObject(templateName) | ||
end | end | ||
self.isTemplatePage = self.templateTitle and mw.title.equals(self.title, self.templateTitle) or false | self.isTemplatePage = self.templateTitle | ||
and mw.title.equals(self.title, self.templateTitle) | |||
or false | |||
end | end | ||
-- Process data for collapsible text fields. At the moment these are only used in {{ambox}}. | -- Process data for collapsible text fields. At the moment these are only | ||
-- used in {{ambox}}. | |||
if self.useCollapsibleTextFields then | if self.useCollapsibleTextFields then | ||
-- Get the self.issue value. | -- Get the self.issue value. | ||
Line 261: | Line 289: | ||
-- Get the self.talk value. | -- Get the self.talk value. | ||
local talk = args.talk | local talk = args.talk | ||
-- Show talk links on the template page or template subpages if the talk | |||
-- parameter is blank. | |||
if talk == '' | |||
and self.templateTitle | and self.templateTitle | ||
and (mw.title.equals(self.templateTitle, self.title) or self.title:isSubpageOf(self.templateTitle)) | and ( | ||
mw.title.equals(self.templateTitle, self.title) | |||
or self.title:isSubpageOf(self.templateTitle) | |||
) | |||
then | then | ||
talk = '#' | talk = '#' | ||
Line 270: | Line 303: | ||
end | end | ||
if talk then | if talk then | ||
-- If the talk value is a talk page, make a link to that page. Else assume that it's a section heading, | -- If the talk value is a talk page, make a link to that page. Else | ||
-- assume that it's a section heading, and make a link to the talk | |||
-- page of the current page with that section heading. | |||
local talkTitle = getTitleObject(talk) | local talkTitle = getTitleObject(talk) | ||
local talkArgIsTalkPage = true | local talkArgIsTalkPage = true | ||
if not talkTitle or not talkTitle.isTalkPage then | if not talkTitle or not talkTitle.isTalkPage then | ||
talkArgIsTalkPage = false | talkArgIsTalkPage = false | ||
talkTitle = getTitleObject(self.title.text, mw.site.namespaces[self.title.namespace].talk.id) | talkTitle = getTitleObject( | ||
self.title.text, | |||
mw.site.namespaces[self.title.namespace].talk.id | |||
) | |||
end | end | ||
if talkTitle and talkTitle.exists then | if talkTitle and talkTitle.exists then | ||
local talkText = 'Relevant discussion may be found on' | local talkText = 'Relevant discussion may be found on' | ||
if talkArgIsTalkPage then | if talkArgIsTalkPage then | ||
talkText = format('%s [[%s|%s]].', talkText, talk, talkTitle.prefixedText) | talkText = format( | ||
'%s [[%s|%s]].', | |||
talkText, | |||
talk, | |||
talkTitle.prefixedText | |||
) | |||
else | else | ||
talkText = format('%s the [[%s#%s|talk page]].', talkText, talkTitle.prefixedText, talk) | talkText = format( | ||
'%s the [[%s#%s|talk page]].', | |||
talkText, | |||
talkTitle.prefixedText, | |||
talk | |||
) | |||
end | end | ||
self.talk = talkText | self.talk = talkText | ||
Line 303: | Line 350: | ||
end | end | ||
-- Set the non-collapsible text field. At the moment this is used by all box types other than ambox, | -- Set the non-collapsible text field. At the moment this is used by all box | ||
-- types other than ambox, and also by ambox when small=yes. | |||
if self.isSmall then | if self.isSmall then | ||
self.text = args.smalltext or args.text | self.text = args.smalltext or args.text | ||
Line 328: | Line 375: | ||
self.imageLeft = imageLeft | self.imageLeft = imageLeft | ||
if not imageLeft then | if not imageLeft then | ||
local imageSize = self.isSmall and (cfg.imageSmallSize or '30x30px') or '40x40px' | local imageSize = self.isSmall | ||
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage or 'Imbox notice.png', imageSize) | and (cfg.imageSmallSize or '30x30px') | ||
or '40x40px' | |||
self.imageLeft = format('[[File:%s|%s|link=|alt=]]', self.typeImage | |||
or 'Imbox notice.png', imageSize) | |||
end | end | ||
end | end | ||
Line 360: | Line 410: | ||
local preposition = 'from' | local preposition = 'from' | ||
for _, num in ipairs(self.categoryParamNums) do | for _, num in ipairs(self.categoryParamNums) do | ||
local mainCat = args['cat' .. tostring(num)] or args['category' .. tostring(num)] | local mainCat = args['cat' .. tostring(num)] | ||
or args['category' .. tostring(num)] | |||
local allCat = args['all' .. tostring(num)] | local allCat = args['all' .. tostring(num)] | ||
mainCat = type(mainCat) == 'string' and mainCat | mainCat = type(mainCat) == 'string' and mainCat | ||
Line 369: | Line 420: | ||
catTitle = getTitleObject('Category:' .. catTitle) | catTitle = getTitleObject('Category:' .. catTitle) | ||
if not catTitle or not catTitle.exists then | if not catTitle or not catTitle.exists then | ||
self:addCat('main', 'Articles with invalid date parameter in template') | self:addCat( | ||
'main', | |||
'Articles with invalid date parameter in template' | |||
) | |||
end | end | ||
elseif mainCat and (not date or date == '') then | elseif mainCat and (not date or date == '') then | ||
Line 426: | Line 480: | ||
end | end | ||
-- Convert category tables to strings and pass them through [[Module:Category handler]]. | -- Convert category tables to strings and pass them through | ||
-- [[Module:Category handler]]. | |||
self.categories = categoryHandler{ | self.categories = categoryHandler{ | ||
main = tconcat(self.mainCats or {}), | main = tconcat(self.mainCats or {}), | ||
Line 462: | Line 517: | ||
.cssText(self.style) | .cssText(self.style) | ||
.attr('role', 'presentation') | .attr('role', 'presentation') | ||
for attr, val in pairs(self.attrs or {}) do | |||
boxTable | |||
.attr(attr, val) | |||
end | |||
-- Add the left-hand image. | -- Add the left-hand image. | ||
Line 468: | Line 527: | ||
local imageLeftCell = row.tag('td').addClass('mbox-image') | local imageLeftCell = row.tag('td').addClass('mbox-image') | ||
if self.imageCellDiv then | if self.imageCellDiv then | ||
-- If we are using a div, redefine imageLeftCell so that the image is inside it. | -- If we are using a div, redefine imageLeftCell so that the image | ||
-- is inside it. Divs use style="width: 52px;", which limits the | |||
-- image width to 52px. If any images in a div are wider than that, | |||
-- they may overlap with the text or cause other display problems. | |||
imageLeftCell = imageLeftCell.tag('div').css('width', '52px') | imageLeftCell = imageLeftCell.tag('div').css('width', '52px') | ||
end | end | ||
Line 477: | Line 536: | ||
.wikitext(self.imageLeft) | .wikitext(self.imageLeft) | ||
elseif self.imageEmptyCell then | elseif self.imageEmptyCell then | ||
-- Some message boxes define an empty cell if no image is specified, and some don't. | -- Some message boxes define an empty cell if no image is specified, and | ||
-- some don't. The old template code in templates where empty cells are | |||
-- specified gives the following hint: "No image. Cell with some width | |||
-- or padding necessary for text cell to have 100% width." | |||
row.tag('td') | row.tag('td') | ||
.addClass('mbox-empty-cell') | .addClass('mbox-empty-cell') | ||
Line 488: | Line 548: | ||
local textCell = row.tag('td').addClass('mbox-text') | local textCell = row.tag('td').addClass('mbox-text') | ||
if self.useCollapsibleTextFields then | if self.useCollapsibleTextFields then | ||
-- The message box uses advanced text parameters that allow things to be collapsible. At the | -- The message box uses advanced text parameters that allow things to be | ||
-- collapsible. At the moment, only ambox uses this. | |||
textCell | textCell | ||
.cssText(self.textstyle) | .cssText(self.textstyle) | ||
Line 522: | Line 582: | ||
local imageRightCell = row.tag('td').addClass('mbox-imageright') | local imageRightCell = row.tag('td').addClass('mbox-imageright') | ||
if self.imageCellDiv then | if self.imageCellDiv then | ||
imageRightCell = imageRightCell.tag('div').css('width', '52px') | -- If we are using a div, redefine imageRightCell so that the image | ||
-- is inside it. | |||
imageRightCell = imageRightCell.tag('div').css('width', '52px') | |||
end | end | ||
imageRightCell | imageRightCell | ||
Line 543: | Line 605: | ||
.tag('div') | .tag('div') | ||
.css('text-align', 'center') | .css('text-align', 'center') | ||
.wikitext(format('This message box is using an invalid "type=%s" parameter and needs fixing.', self.type or '')) | .wikitext(format( | ||
'This message box is using an invalid "type=%s" parameter and needs fixing.', | |||
self.type or '' | |||
)) | |||
end | end | ||