Module:Message box: Difference between revisions
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.
| No edit summary | m>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 | ||