Jump to content

Module:Message box

Permanently protected module
From Wikipedia, the free encyclopedia

require('strict')localgetArgslocalyesno=require('Module:Yesno')locallang=mw.language.getContentLanguage()localCONFIG_MODULE='Module:Message box/configuration'localDEMOSPACES={talk='tmbox',image='imbox',file='imbox',category='cmbox',article='ambox',main='ambox'}---------------------------------------------------------------------------------- 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,...)ifsuccessthenreturntitleendendlocalfunctionunion(t1,t2)-- Returns the union of two arrays.localvals={}fori,vinipairs(t1)dovals[v]=trueendfori,vinipairs(t2)dovals[v]=trueendlocalret={}forkinpairs(vals)dotable.insert(ret,k)endtable.sort(ret)returnretendlocalfunctiongetArgNums(args,prefix)localnums={}fork,vinpairs(args)dolocalnum=mw.ustring.match(tostring(k),'^'..prefix..'([1-9]%d*)$')ifnumthentable.insert(nums,tonumber(num))endendtable.sort(nums)returnnumsend---------------------------------------------------------------------------------- Box class definition--------------------------------------------------------------------------------localMessageBox={}MessageBox.__index=MessageBoxfunctionMessageBox.new(boxType,args,cfg)args=argsor{}localobj={}-- 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.cfgthenlocalns=obj.title.namespace-- boxType is "mbox" or invalid inputifargs.demospaceandargs.demospace~=''then-- implement demospace parameter of mboxlocaldemospace=string.lower(args.demospace)ifDEMOSPACES[demospace]then-- use template from DEMOSPACESobj.cfg=cfg[DEMOSPACES[demospace]]elseifstring.find(demospace,'talk')then-- demo as a talk pageobj.cfg=cfg.tmboxelse-- default to omboxobj.cfg=cfg.omboxendelseifns==0thenobj.cfg=cfg.ambox-- main namespaceelseifns==6thenobj.cfg=cfg.imbox-- file namespaceelseifns==14thenobj.cfg=cfg.cmbox-- category namespaceelselocalnsTable=mw.site.namespaces[ns]ifnsTableandnsTable.isTalkthenobj.cfg=cfg.tmbox-- any talk namespaceelseobj.cfg=cfg.ombox-- other namespaces or invalid inputendendend-- Set the arguments, and remove all blank arguments except for the ones-- listed in cfg.allowBlankParams.dolocalnewArgs={}fork,vinpairs(args)doifv~=''thennewArgs[k]=vendendfori,paraminipairs(obj.cfg.allowBlankParamsor{})donewArgs[param]=args[param]endobj.args=newArgsend-- Define internal data structure.obj.categories={}obj.classes={}-- For lazy loading of [[Module:Category handler]].obj.hasCategories=falsereturnsetmetatable(obj,MessageBox)endfunctionMessageBox:addCat(ns,cat,sort)ifnotcatthenreturnnilendifsortthencat=string.format('[[Category:%s|%s]]',cat,sort)elsecat=string.format('[[Category:%s]]',cat)endself.hasCategories=trueself.categories[ns]=self.categories[ns]or{}table.insert(self.categories[ns],cat)endfunctionMessageBox:addClass(class)ifnotclassthenreturnnilendtable.insert(self.classes,class)endfunctionMessageBox:setParameters()localargs=self.argslocalcfg=self.cfg-- Get type data.self.type=args.typelocaltypeData=cfg.types[self.type]self.invalidTypeError=cfg.showInvalidTypeErrorandself.typeandnottypeDatatypeData=typeDataorcfg.types[cfg.default]self.typeClass=typeData.classself.typeImage=typeData.imageself.typeImageNeedsLink=typeData.imageNeedsLink-- 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.smallParamornotcfg.smallParamandyesno(args.small))-- Add attributes, classes and styles.self.id=args.idself.name=args.nameifself.namethenself:addClass('box-'..string.gsub(self.name,' ','_'))endifyesno(args.plainlinks)~=falsethenself:addClass('plainlinks')endfor_,classinipairs(cfg.classesor{})doself:addClass(class)endifself.isSmallthenself:addClass(cfg.smallClassor'mbox-small')endself:addClass(self.typeClass)self:addClass(args.class)self.style=args.styleself.attrs=args.attrs-- Set text style.self.textstyle=args.textstyle-- Set image classes.self.imageRightClass=args.imagerightclassorargs.imageclassself.imageLeftClass=args.imageleftclassorargs.imageclass-- 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.useCollapsibleTextFieldsifself.useCollapsibleTextFieldsorcfg.templateCategoryandcfg.templateCategoryRequireNamethenifself.namethenlocaltemplateName=mw.ustring.match(self.name,'^[tT][eE][mM][pP][lL][aA][tT][eE][%s_]*:[%s_]*(.*)$')orself.nametemplateName='Template:'..templateNameself.templateTitle=getTitleObject(templateName)endself.isTemplatePage=self.templateTitleandmw.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.smalltextthenself.issue=args.smalltextelselocalsectifargs.sect==''thensect='This '..(cfg.sectionDefaultor'page')elseiftype(args.sect)=='string'thensect='This '..args.sectendlocalissue=args.issueissue=type(issue)=='string'andissue~=''andissueornillocaltext=args.texttext=type(text)=='string'andtextornillocalissues={}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.templateTitleand(mw.title.equals(self.templateTitle,self.title)orself.title:isSubpageOf(self.templateTitle))thentalk='#'elseiftalk==''thentalk=nilendiftalkthen-- 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=trueifnottalkTitleornottalkTitle.isTalkPagethentalkArgIsTalkPage=falsetalkTitle=getTitleObject(self.title.text,mw.site.namespaces[self.title.namespace].talk.id)endiftalkTitleandtalkTitle.existsthenlocaltalkTextifself.isSmallthenlocaltalkLink=talkArgIsTalkPageandtalkor(talkTitle.prefixedText..(talk=='#'and''or'#')..talk)talkText=string.format('([[%s|talk]])',talkLink)elsetalkText='Relevant discussion may be found on'iftalkArgIsTalkPagethentalkText=string.format('%s [[%s|%s]].',talkText,talk,talkTitle.prefixedText)elsetalkText=string.format('%s the [[%s'..(talk=='#'and''or'#')..'%s|talk page]].',talkText,talkTitle.prefixedText,talk)endendself.talk=talkTextendend-- Get other values.self.fix=args.fix~=''andargs.fixornillocaldateifargs.dateandargs.date~=''thendate=args.dateelseifargs.date==''andself.isTemplatePagethendate=lang:formatDate('F Y')endifdatethenself.date=string.format(" <span class='date-container'><i>(<span class='date'>%s</span>)</i></span>",date)endself.info=args.infoifyesno(args.removalnotice)thenself.removalNotice=cfg.removalNoticeendend-- 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.isSmallthenself.text=args.smalltextorargs.textelseself.text=args.textend-- Set the below row.self.below=cfg.belowandargs.below-- General image settings.self.imageCellDiv=notself.isSmallandcfg.imageCellDivself.imageEmptyCell=cfg.imageEmptyCell-- Left image settings.localimageLeft=self.isSmallandargs.smallimageorargs.imageifcfg.imageCheckBlankandimageLeft~='blank'andimageLeft~='none'ornotcfg.imageCheckBlankandimageLeft~='none'thenself.imageLeft=imageLeftifnotimageLeftthenlocalimageSize=self.isSmalland(cfg.imageSmallSizeor'30x30px')or'40x40px'self.imageLeft=string.format('[[File:%s|%s%s|alt=]]',self.typeImageor'Information icon4.svg',imageSize,self.typeImageNeedsLinkand""or"|link=")endend-- Right image settings.localimageRight=self.isSmallandargs.smallimagerightorargs.imagerightifnot(cfg.imageRightNoneandimageRight=='none')thenself.imageRight=imageRightend-- set templatestylesself.base_templatestyles=cfg.templatestylesself.templatestyles=args.templatestylesendfunctionMessageBox:setMainspaceCategories()localargs=self.argslocalcfg=self.cfgifnotcfg.allowMainspaceCategoriesthenreturnnilendlocalnums={}for_,prefixinipairs{'cat','category','all'}doargs[prefix..'1']=args[prefix]nums=union(nums,getArgNums(args,prefix))end-- The following is roughly equivalent to the old {{Ambox/category}}.localdate=args.datedate=type(date)=='string'anddatelocalpreposition='from'for_,numinipairs(nums)dolocalmainCat=args['cat'..tostring(num)]orargs['category'..tostring(num)]localallCat=args['all'..tostring(num)]mainCat=type(mainCat)=='string'andmainCatallCat=type(allCat)=='string'andallCatifmainCatanddateanddate~=''thenlocalcatTitle=string.format('%s %s %s',mainCat,preposition,date)self:addCat(0,catTitle)catTitle=getTitleObject('Category:'..catTitle)ifnotcatTitleornotcatTitle.existsthenself:addCat(0,'Articles with invalid date parameter in template')endelseifmainCatand(notdateordate=='')thenself:addCat(0,mainCat)endifallCatthenself:addCat(0,allCat)endendendfunctionMessageBox:setTemplateCategories()localargs=self.argslocalcfg=self.cfg-- Add template categories.ifcfg.templateCategorythenifcfg.templateCategoryRequireNamethenifself.isTemplatePagethenself:addCat(10,cfg.templateCategory)endelseifnotself.title.isSubpagethenself:addCat(10,cfg.templateCategory)endend-- Add template error categories.ifcfg.templateErrorCategorythenlocaltemplateErrorCategory=cfg.templateErrorCategorylocaltemplateCat,templateSortifnotself.nameandnotself.title.isSubpagethentemplateCat=templateErrorCategoryelseifself.isTemplatePagethenlocalparamsToCheck=cfg.templateErrorParamsToCheckor{}localcount=0fori,paraminipairs(paramsToCheck)doifnotargs[param]thencount=count+1endendifcount>0thentemplateCat=templateErrorCategorytemplateSort=tostring(count)endifself.categoryNumsand#self.categoryNums>0thentemplateCat=templateErrorCategorytemplateSort='C'endendself:addCat(10,templateCat,templateSort)endendfunctionMessageBox:setAllNamespaceCategories()-- Set categories for all namespaces.ifself.invalidTypeErrorthenlocalallSort=(self.title.namespace==0and'Main:'or'')..self.title.prefixedTextself:addCat('all','Wikipedia message box parameter needs fixing',allSort)endifself.isSubstitutedthenself:addCat('all','Pages with incorrectly substituted templates')endendfunctionMessageBox:setCategories()ifself.title.namespace==0thenself:setMainspaceCategories()elseifself.title.namespace==10thenself:setTemplateCategories()endself:setAllNamespaceCategories()endfunctionMessageBox: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}endfunctionMessageBox:export()localroot=mw.html.create()-- Add the subst check error.ifself.isSubstitutedandself.namethenroot: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('}}')))endlocalframe=mw.getCurrentFrame()root:wikitext(frame:extensionTag{name='templatestyles',args={src=self.base_templatestyles},})-- Add support for a single custom templatestyles sheet. Undocumented as-- need should be limited and many templates using mbox are substed; we-- don't want to spread templatestyles sheets around to arbitrary placesifself.templatestylesthenroot:wikitext(frame:extensionTag{name='templatestyles',args={src=self.templatestyles},})end-- Create the box table.localboxTable=root:tag('table')boxTable:attr('id',self.idornil)fori,classinipairs(self.classesor{})doboxTable:addClass(classornil)endboxTable:cssText(self.styleornil):attr('role','presentation')ifself.attrsthenboxTable:attr(self.attrs)end-- Add the left-hand image.localrow=boxTable:tag('tr')ifself.imageLeftthenlocalimageLeftCell=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'):addClass('mbox-image-div')endimageLeftCell:addClass(self.imageLeftClass):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')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)thentextCellDiv:tag('span'):addClass('hide-when-compact'):wikitext(self.talkand(' '..self.talk)ornil):wikitext(self.fixand(' '..self.fix)ornil)endtextCellDiv:wikitext(self.dateand(' '..self.date)ornil)ifself.infoandnotself.isSmallthentextCellDiv:tag('span'):addClass('hide-when-compact'):wikitext(self.infoand(' '..self.info)ornil)endifself.removalNoticethentextCellDiv:tag('span'):addClass('hide-when-compact'):tag('i'):wikitext(string.format(" (%s)",self.removalNotice))endelse-- Default text formatting - anything goes.textCell:cssText(self.textstyleornil):wikitext(self.textornil)end-- Add the right-hand image.ifself.imageRightthenlocalimageRightCell=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'):addClass('mbox-image-div')endimageRightCell:addClass(self.imageRightClass):wikitext(self.imageRightornil)end-- Add the below row.ifself.belowthenboxTable: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.invalidTypeErrorthenroot:tag('div'):addClass('mbox-invalid-type'):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}endfunctionp.main(boxType,args,cfgTables)localbox=MessageBox.new(boxType,args,cfgTablesormw.loadData(CONFIG_MODULE))box:setParameters()box:setCategories()returnbox:export()endfunctionmt.__index(t,k)returnfunction(frame)ifnotgetArgsthengetArgs=require('Module:Arguments').getArgsendreturnt.main(k,getArgs(frame,{trim=false,removeBlanks=false}))endendreturnsetmetatable(p,mt)
close