Jump to content
MediaWiki

Module:Message box

From mediawiki.org
Module documentation
This module is used in system messages.
Changes to it can cause immediate changes to the MediaWiki user interface. To avoid large-scale disruption, any changes should first be tested in this module's /sandbox or /testcases subpage, or in your own user space.The tested changes can then be added in one single edit to this module. Please discuss any changes on the talk page before implementing them.
This module is rated as ready for general use. It has reached a mature form and is thought to be bug-free and ready for use wherever appropriate. It is ready to mention on help pages and other resources as an option for new users to learn. To reduce server load and bad output, it should be improved by sandbox testing rather than repeated trial-and-error editing.
This module is subject to cascading protection. It is a highly visible module in use by a very large number of pages. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing.

This is a meta-module that implements the message box templates {{mbox}}, {{ambox}}, {{cmbox}}, {{fmbox}}, {{imbox}}, {{ombox}} and {{tmbox}}. It is intended to be used from Lua modules, and should not be used directly from wiki pages. If you want to use this module's functionality from a wiki page, please use the individual message box templates instead.

Usage

To use this module from another Lua module, first you need to load it.

localmessageBox=require('Module:Message box')

To create a message box, use the main function. It takes two parameters:

  • the first is the box type (as a string).
  • the second is a table containing the message box parameters.
localbox=messageBox.main(boxType,{
param1=param1,
param2=param2,
-- More parameters...
})

There are seven available box types:

Box type Template Purpose
mbox {{mbox}} For message boxes to be used in multiple namespaces
ambox {{ambox}} For article message boxes
cmbox {{cmbox}} For category message boxes
fmbox {{fmbox}} For interface message boxes
imbox {{imbox}} For file namespace message boxes
tmbox {{tmbox}} For talk page message boxes
ombox {{ombox}} For message boxes in other namespaces

See the template page of each box type for the available parameters.

Usage from #invoke

As well as the main function, this module has separate functions for each box type. They are accessed using the code {{#invoke:Message box|mbox|...}}, {{#invoke:Message box|ambox|...}}, etc. These will work when called from other modules, but they access code used to process arguments passed from {{#invoke:...}}, and so calling them will be less efficient than calling main.

Technical details

The module uses the same basic code for each of the templates listed above; the differences between each of them are configured using the data at Module:Message box/configuration.

The above documentation is transcluded from Module:Message box/doc. (edit | history)
Editors can experiment in this module’s sandbox (edit | diff) and testcases (create) pages.
Subpages of this module.

 -- This is a meta-module for producing message box templates, including
 -- {{mbox}}, {{ambox}}, {{imbox}}, {{tmbox}}, {{ombox}}, {{cmbox}} and {{fmbox}}.

 -- Load necessary modules.
 require('strict')
 localgetArgs
 localyesno=require('Module:Yesno')

 -- Get a language object for formatDate and ucfirst.
 locallang=mw.language.getContentLanguage()

 -- Define constants
 localCONFIG_MODULE='Module:Message box/configuration'
 localDEMOSPACES={talk='tmbox',image='imbox',file='imbox',category='cmbox',article='ambox',main='ambox'}
 localTEMPLATE_STYLES='Module:Message box/%s.css'

 --------------------------------------------------------------------------------
 -- Helper functions
 --------------------------------------------------------------------------------

 localfunctiongetTitleObject(...)
 -- Get the title object, passing the function through pcall
 -- in case we are over the expensive function count limit.
 localsuccess,title=pcall(mw.title.new,...)
 ifsuccessthen
 returntitle
 end
 end

 localfunctionunion(t1,t2)
 -- Returns the union of two arrays.
 localvals={}
 fori,vinipairs(t1)do
 vals[v]=true
 end
 fori,vinipairs(t2)do
 vals[v]=true
 end
 localret={}
 forkinpairs(vals)do
 table.insert(ret,k)
 end
 table.sort(ret)
 returnret
 end

 localfunctiongetArgNums(args,prefix)
 localnums={}
 fork,vinpairs(args)do
 localnum=mw.ustring.match(tostring(k),'^'..prefix..'([1-9]%d*)$')
 ifnumthen
 table.insert(nums,tonumber(num))
 end
 end
 table.sort(nums)
 returnnums
 end

 --------------------------------------------------------------------------------
 -- Box class definition
 --------------------------------------------------------------------------------

 localMessageBox={}
 MessageBox.__index=MessageBox

 functionMessageBox.new(boxType,args,cfg)
 args=argsor{}
 localobj={}

 obj.boxType=boxType

 -- Set the title object and the namespace.
 obj.title=getTitleObject(args.page)ormw.title.getCurrentTitle()

 -- Set the config for our box type.
 obj.cfg=cfg[boxType]
 ifnotobj.cfgthen
 localns=obj.title.namespace
 -- boxType is "mbox" or invalid input
 ifargs.demospaceandargs.demospace~=''then
 -- implement demospace parameter of mbox
 localdemospace=string.lower(args.demospace)
 ifDEMOSPACES[demospace]then
 -- use template from DEMOSPACES
 obj.cfg=cfg[DEMOSPACES[demospace]]
 obj.boxType=DEMOSPACES[demospace]
 elseifstring.find(demospace,'talk')then
 -- demo as a talk page
 obj.cfg=cfg.tmbox
 obj.boxType='tmbox'
 else
 -- default to ombox
 obj.cfg=cfg.ombox
 obj.boxType='ombox'
 end
 elseifns==0then
 obj.cfg=cfg.ambox-- main namespace
 obj.boxType='ambox'
 elseifns==6then
 obj.cfg=cfg.imbox-- file namespace
 obj.boxType='imbox'
 elseifns==14then
 obj.cfg=cfg.cmbox-- category namespace
 obj.boxType='cmbox'
 else
 localnsTable=mw.site.namespaces[ns]
 ifnsTableandnsTable.isTalkthen
 obj.cfg=cfg.tmbox-- any talk namespace
 obj.boxType='tmbox'
 else
 obj.cfg=cfg.ombox-- other namespaces or invalid input
 obj.boxType='ombox'
 end
 end
 end

 -- Set the arguments, and remove all blank arguments except for the ones
 -- listed in cfg.allowBlankParams.
 do
 localnewArgs={}
 fork,vinpairs(args)do
 ifv~=''then
 newArgs[k]=v
 end
 end
 fori,paraminipairs(obj.cfg.allowBlankParamsor{})do
 newArgs[param]=args[param]
 end
 obj.args=newArgs
 end

 -- Define internal data structure.
 obj.categories={}
 obj.classes={}
 -- For lazy loading of [[Module:Category handler]].
 obj.hasCategories=false

 returnsetmetatable(obj,MessageBox)
 end

 functionMessageBox:addCat(ns,cat,sort)
 ifnotcatthen
 returnnil
 end
 ifsortthen
 cat=string.format('[[Category:%s|%s]]',cat,sort)
 else
 cat=string.format('[[Category:%s]]',cat)
 end
 self.hasCategories=true
 self.categories[ns]=self.categories[ns]or{}
 table.insert(self.categories[ns],cat)
 end

 functionMessageBox:addClass(class)
 ifnotclassthen
 returnnil
 end
 self.classes[class]=1
 end

 functionMessageBox:removeClass(class)
 ifnotclassthen
 returnnil
 end
 self.classes[class]=nil
 end

 functionMessageBox:setParameters()
 localargs=self.args
 localcfg=self.cfg

 -- Get type data.
 self.type=args.type
 localtypeData=cfg.types[self.type]
 self.invalidTypeError=cfg.showInvalidTypeError
 andself.type
 andnottypeData
 typeData=typeDataorcfg.types[cfg.default]
 self.typeClass=typeData.class
 self.typeImage=typeData.image

 -- Find if the box has been wrongly substituted.
 self.isSubstituted=cfg.substCheckandargs.subst=='SUBST'

 -- Find whether we are using a small message box.
 self.isSmall=cfg.allowSmalland(
 cfg.smallParamandargs.small==cfg.smallParam
 ornotcfg.smallParamandyesno(args.small)
 )

 -- Add attributes, classes and styles.
 self.id=args.id
 self.name=args.name
 for_,classinipairs(cfg.classesor{})do
 self:addClass(class)
 end
 ifself.namethen
 self:addClass('box-'..string.gsub(self.name,' ','_'))
 end
 localplainlinks=yesno(args.plainlinks)
 ifplainlinks==truethen
 self:addClass('plainlinks')
 elseifplainlinks==falsethen
 self:removeClass('plainlinks')
 end
 ifself.isSmallthen
 self:addClass(cfg.smallClassor'mbox-small')
 end
 self:addClass(self.typeClass)
 self:addClass(args.class)
 self.style=args.style
 self.attrs=args.attrs

 -- Set text style.
 self.textstyle=args.textstyle

 -- 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
 ifself.useCollapsibleTextFields
 orcfg.templateCategory
 andcfg.templateCategoryRequireName
 then
 ifself.namethen
 localtemplateName=mw.ustring.match(
 self.name,
 '^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$'
 )orself.name
 templateName='Template:'..templateName
 self.templateTitle=getTitleObject(templateName)
 end
 self.isTemplatePage=self.templateTitle
 andmw.title.equals(self.title,self.templateTitle)
 end

 -- Process data for collapsible text fields. At the moment these are only
 -- used in {{ambox}}.
 ifself.useCollapsibleTextFieldsthen
 -- Get the self.issue value.
 ifself.isSmallandargs.smalltextthen
 self.issue=args.smalltext
 else
 localsect
 ifargs.sect==''then
 sect='This '..(cfg.sectionDefaultor'page')
 elseiftype(args.sect)=='string'then
 sect='This '..args.sect
 end
 localissue=args.issue
 issue=type(issue)=='string'andissue~=''andissueornil
 localtext=args.text
 text=type(text)=='string'andtextornil
 localissues={}
 table.insert(issues,sect)
 table.insert(issues,issue)
 table.insert(issues,text)
 self.issue=table.concat(issues,' ')
 end

 -- Get the self.talk value.
 localtalk=args.talk
 -- Show talk links on the template page or template subpages if the talk
 -- parameter is blank.
 iftalk==''
 andself.templateTitle
 and(
 mw.title.equals(self.templateTitle,self.title)
 orself.title:isSubpageOf(self.templateTitle)
 )
 then
 talk='#'
 elseiftalk==''then
 talk=nil
 end
 iftalkthen
 -- 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.
 localtalkTitle=getTitleObject(talk)
 localtalkArgIsTalkPage=true
 ifnottalkTitleornottalkTitle.isTalkPagethen
 talkArgIsTalkPage=false
 talkTitle=getTitleObject(
 self.title.text,
 mw.site.namespaces[self.title.namespace].talk.id
 )
 end
 iftalkTitleandtalkTitle.existsthen
 localtalkText='Relevant discussion may be found on'
 iftalkArgIsTalkPagethen
 talkText=string.format(
 '%s [[%s|%s]].',
 talkText,
 talk,
 talkTitle.prefixedText
 )
 else
 talkText=string.format(
 '%s the [[%s#%s|talk page]].',
 talkText,
 talkTitle.prefixedText,
 talk
 )
 end
 self.talk=talkText
 end
 end

 -- Get other values.
 self.fix=args.fix~=''andargs.fixornil
 localdate
 ifargs.dateandargs.date~=''then
 date=args.date
 elseifargs.date==''andself.isTemplatePagethen
 date=lang:formatDate('F Y')
 end
 ifdatethen
 self.date=string.format(" <small class='date-container'>''(<span class='date'>%s</span>)''</small>",date)
 end
 self.info=args.info
 ifyesno(args.removalnotice)then
 self.removalNotice=cfg.removalNotice
 end
 end

 -- 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.
 ifself.isSmallthen
 self.text=args.smalltextorargs.text
 else
 self.text=args.text
 end

 -- Set the below row.
 self.below=cfg.belowandargs.below

 -- General image settings.
 self.imageCellDiv=notself.isSmallandcfg.imageCellDiv
 self.imageEmptyCell=cfg.imageEmptyCell
 ifcfg.imageEmptyCellStylethen
 self.imageEmptyCellStyle='border:none;padding:0px;width:1px'
 end

 -- Left image settings.
 localimageLeft=self.isSmallandargs.smallimageorargs.image
 ifcfg.imageCheckBlankandimageLeft~='blank'andimageLeft~='none'
 ornotcfg.imageCheckBlankandimageLeft~='none'
 then
 self.imageLeft=imageLeft
 ifnotimageLeftthen
 localimageSize=self.isSmall
 and(cfg.imageSmallSizeor'30x30px')
 or'40x40px'
 self.imageLeft=string.format('[[File:%s|%s|link=|alt=]]',self.typeImage
 or'Information icon4.svg',imageSize)
 end
 end

 -- Right image settings.
 localimageRight=self.isSmallandargs.smallimagerightorargs.imageright
 ifnot(cfg.imageRightNoneandimageRight=='none')then
 self.imageRight=imageRight
 end
 end

 functionMessageBox:setMainspaceCategories()
 localargs=self.args
 localcfg=self.cfg

 ifnotcfg.allowMainspaceCategoriesthen
 returnnil
 end

 localnums={}
 for_,prefixinipairs{'cat','category','all'}do
 args[prefix..'1']=args[prefix]
 nums=union(nums,getArgNums(args,prefix))
 end

 -- The following is roughly equivalent to the old {{Ambox/category}}.
 localdate=args.date
 date=type(date)=='string'anddate
 localpreposition='from'
 for_,numinipairs(nums)do
 localmainCat=args['cat'..tostring(num)]
 orargs['category'..tostring(num)]
 localallCat=args['all'..tostring(num)]
 mainCat=type(mainCat)=='string'andmainCat
 allCat=type(allCat)=='string'andallCat
 ifmainCatanddateanddate~=''then
 localcatTitle=string.format('%s %s %s',mainCat,preposition,date)
 self:addCat(0,catTitle)
 catTitle=getTitleObject('Category:'..catTitle)
 ifnotcatTitleornotcatTitle.existsthen
 self:addCat(0,'Articles with invalid date parameter in template')
 end
 elseifmainCatand(notdateordate=='')then
 self:addCat(0,mainCat)
 end
 ifallCatthen
 self:addCat(0,allCat)
 end
 end
 end

 functionMessageBox:setTemplateCategories()
 localargs=self.args
 localcfg=self.cfg

 -- Add template categories.
 ifcfg.templateCategorythen
 ifcfg.templateCategoryRequireNamethen
 ifself.isTemplatePagethen
 self:addCat(10,cfg.templateCategory)
 end
 elseifnotself.title.isSubpagethen
 self:addCat(10,cfg.templateCategory)
 end
 end

 -- Add template error categories.
 ifcfg.templateErrorCategorythen
 localtemplateErrorCategory=cfg.templateErrorCategory
 localtemplateCat,templateSort
 ifnotself.nameandnotself.title.isSubpagethen
 templateCat=templateErrorCategory
 elseifself.isTemplatePagethen
 localparamsToCheck=cfg.templateErrorParamsToCheckor{}
 localcount=0
 fori,paraminipairs(paramsToCheck)do
 ifnotargs[param]then
 count=count+1
 end
 end
 ifcount>0then
 templateCat=templateErrorCategory
 templateSort=tostring(count)
 end
 ifself.categoryNumsand#self.categoryNums>0then
 templateCat=templateErrorCategory
 templateSort='C'
 end
 end
 self:addCat(10,templateCat,templateSort)
 end
 end

 functionMessageBox:setAllNamespaceCategories()
 -- Set categories for all namespaces.
 ifself.isSubstitutedthen
 self:addCat('all','Pages with incorrectly substituted templates')
 end
 end

 functionMessageBox:setCategories()
 ifself.title.namespace==0then
 self:setMainspaceCategories()
 elseifself.title.namespace==10then
 self:setTemplateCategories()
 end
 self:setAllNamespaceCategories()
 end

 functionMessageBox:renderCategories()
 ifnotself.hasCategoriesthen
 -- No categories added, no need to pass them to Category handler so,
 -- if it was invoked, it would return the empty string.
 -- So we shortcut and return the empty string.
 return""
 end
 -- Convert category tables to strings and pass them through
 -- [[Module:Category handler]].
 returnrequire('Module:Category handler')._main{
 main=table.concat(self.categories[0]or{}),
 template=table.concat(self.categories[10]or{}),
 all=table.concat(self.categories.allor{}),
 nocat=self.args.nocat,
 page=self.args.page
 }
 end

 functionMessageBox:export()
 localroot=mw.html.create()

 -- Add the subst check error.
 ifself.isSubstitutedandself.namethen
 root:tag('b')
 :addClass('error')
 :wikitext(string.format(
 'Template <code>%s[[Template:%s|%s]]%s</code> has been incorrectly substituted.',
 mw.text.nowiki('{{'),self.name,self.name,mw.text.nowiki('}}')
 ))
 end

 -- Add TemplateStyles
 root:wikitext(mw.getCurrentFrame():extensionTag{
 name='templatestyles',
 args={src=TEMPLATE_STYLES:format(self.boxType)},
 })

 -- Create the box table.
 localboxTable
 -- Check for fmbox because not all interface messages have mw-parser-output
 -- which is necessary for TemplateStyles. Add the wrapper class if it is and
 -- then start the actual mbox, else start the mbox.
 ifself.boxType=='fmbox'then
 boxTable=root:tag('div')
 :addClass('mw-parser-output')
 :tag('table')
 else
 boxTable=root:tag('table')
 end

 boxTable:attr('id',self.idornil)
 forclass,_inpairs(self.classesor{})do
 boxTable:addClass(classornil)
 end
 boxTable
 :cssText(self.styleornil)
 :attr('role','presentation')

 ifself.attrsthen
 boxTable:attr(self.attrs)
 end

 -- Add the left-hand image.
 localrow=boxTable:tag('tr')
 ifself.imageLeftthen
 localimageLeftCell=row:tag('td'):addClass('mbox-image')
 ifself.imageCellDivthen
 -- 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')
 end
 imageLeftCell:wikitext(self.imageLeftornil)
 elseifself.imageEmptyCellthen
 -- 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')
 :addClass('mbox-empty-cell')
 :cssText(self.imageEmptyCellStyleornil)
 end

 -- Add the text.
 localtextCell=row:tag('td'):addClass('mbox-text')
 ifself.useCollapsibleTextFieldsthen
 -- The message box uses advanced text parameters that allow things to be
 -- collapsible. At the moment, only ambox uses this.
 textCell:cssText(self.textstyleornil)
 localtextCellDiv=textCell:tag('div')
 textCellDiv
 :addClass('mbox-text-span')
 :wikitext(self.issueornil)
 if(self.talkorself.fix)andnotself.isSmallthen
 textCellDiv:tag('span')
 :addClass('hide-when-compact')
 :wikitext(self.talkand(' '..self.talk)ornil)
 :wikitext(self.fixand(' '..self.fix)ornil)
 end
 textCellDiv:wikitext(self.dateand(' '..self.date)ornil)
 ifself.infoandnotself.isSmallthen
 textCellDiv
 :tag('span')
 :addClass('hide-when-compact')
 :wikitext(self.infoand(' '..self.info)ornil)
 end
 ifself.removalNoticethen
 textCellDiv:tag('small')
 :addClass('hide-when-compact')
 :tag('i')
 :wikitext(string.format(" (%s)",self.removalNotice))
 end
 else
 -- Default text formatting - anything goes.
 textCell
 :cssText(self.textstyleornil)
 :wikitext(self.textornil)
 end

 -- Add the right-hand image.
 ifself.imageRightthen
 localimageRightCell=row:tag('td'):addClass('mbox-imageright')
 ifself.imageCellDivthen
 -- If we are using a div, redefine imageRightCell so that the image
 -- is inside it.
 imageRightCell=imageRightCell:tag('div'):css('width','52px')
 end
 imageRightCell
 :wikitext(self.imageRightornil)
 end

 -- Add the below row.
 ifself.belowthen
 boxTable:tag('tr')
 :tag('td')
 :attr('colspan',self.imageRightand'3'or'2')
 :addClass('mbox-text')
 :cssText(self.textstyleornil)
 :wikitext(self.belowornil)
 end

 -- Add error message for invalid type parameters.
 ifself.invalidTypeErrorthen
 root:tag('div')
 :css('text-align','center')
 :wikitext(string.format(
 'This message box is using an invalid "type=%s" parameter and needs fixing.',
 self.typeor''
 ))
 end

 -- Add categories.
 root:wikitext(self:renderCategories()ornil)

 returntostring(root)
 end

 --------------------------------------------------------------------------------
 -- Exports
 --------------------------------------------------------------------------------

 localp,mt={},{}

 functionp._exportClasses()
 -- For testing.
 return{
 MessageBox=MessageBox
 }
 end

 functionp.main(boxType,args,cfgTables)
 localbox=MessageBox.new(boxType,args,cfgTablesormw.loadData(CONFIG_MODULE))
 box:setParameters()
 box:setCategories()
 returnbox:export()
 end

 functionmt.__index(t,k)
 returnfunction(frame)
 ifnotgetArgsthen
 getArgs=require('Module:Arguments').getArgs
 end
 returnt.main(k,getArgs(frame,{trim=false,removeBlanks=false}))
 end
 end

 returnsetmetatable(p,mt)

AltStyle によって変換されたページ (->オリジナル) /