This module makes indexes of articles for theSignpost. It has two main functions:
The article data is stored in index modules organised by year, likeModule:Signpost/index/2005,Module:Signpost/index/2006, etc. You can see the full list of index moduleshere. The data for all Signpost articles for a given year goes in that year's index module.
It is possible to edit the index modules by hand, but the recommended way is to use theSignpostTagger gadget. With SignpostTagger you can edit article data directly from Signpost article pages, and using it eliminates the possibility of making formatting errors or putting the data in the wrong place.
The index modules each contain a list of articles for that year. Each article has the following data points:
date: The date the article was published, in YYYY-MM-DD formatsubpage: The subpage of the article. For example, for the special report "Adminship from the German perspective" located atWikipedia:Wikipedia Signpost/2012-10-22/Special report, the subpage is "Special report".title: The article's title.authors: Array listing authors of the article, as read by Wegweiser and SignpostTagger (based on displayed text from the author field, not links).tags: A list of tags for the article. For example, the special report mentioned above has the tags "germanwikipedia", "reformingrfa", "requestsforadminship", and "specialreport" (optional).views: Set of key-value pairs for views over seven intervals:d007 (7 days),d015 (15 days),d030,d060,d090,d120,d180.subhead: Article subheading (not normally displayed in the article, but can be parsed out of the "RSS description" template).piccy: Set of key-value pairs for associating an image with an article (optional).filename: Image credit to display as overlay (i.e. author of image).license: Short string for image license in overlay (i.e. "CC 4.0 BY-SA").scaling: Scaling, width-based: default is 300, which is the width of the snippet template.xoffset: X-offset (i.e. how many pixels to crop from theleft if scaling gives an image wider than 300px).yoffset: Y-offset (i.e. how many pixels to crop from thetop if scaling gives an image taller than 300px).Tags are used to classify articles. For example, you can find all of the humourous articles by using thearticle list maker template to list all articles with the tag "humour". It is also possible to specify aliases for tags. For example, "humor" is an alias for the "humour" tag, so when you are tagging an article with SignpostTagger you can use either one of them. Tag aliases are stored atModule:Signpost/aliases.
Wikipedia:Wikipedia Signpost/Templates/Article list maker, sort by tag (arbitrationreport), limit 5, include subhead
2024-12-24, News and notes:Responsibilities and liabilities as a "Very Large Online Platform", by BrilocalINDEX_MODULE='Module:Signpost/index'locallang=mw.language.getContentLanguage()locallibraryUtil=require('libraryUtil')localcheckType=libraryUtil.checkTypelocalcheckTypeForNamedArg=libraryUtil.checkTypeForNamedArg---------------------------------------------------------------------------------- Article class--------------------------------------------------------------------------------localArticle={}Article.__index=ArticleArticle.viewSpans={7,15,30,60,90,120,180}Article.rowMethods={page='getPage',fullpage='getFullPage',date='getDate',title='getTitle',subpage='getSubpage',author='getAuthor',subhead='getSubhead',}-- Register viewsNN row methodsfor_,spaninipairs(Article.viewSpans)doArticle.rowMethods["views"..span]="getViews"..spanendfunctionArticle.new(data)localself=setmetatable({},Article)self.data=dataself.matchedTags={}returnselfendfunctionArticle:getSortKey()returnself.data.sortKeyendfunctionArticle:getPage()returnself.data.pageendfunctionArticle:getDate()returnself.data.dateendfunctionArticle:getTitle()returnself.data.titleendfunctionArticle:getSubpage()returnself.data.subpageendfunctionArticle:getAuthor()returnself.data.authors[1]endfunctionArticle:getAuthors()returnself.data.authorsend-- Add getViewsNN methodsfor_,spaninipairs(Article.viewSpans)doArticle["getViews"..span]=function(self)ifself.data.viewsthenreturnself.data.views[string.format("d%03d",span)]elsereturnnilendendendfunctionArticle:getSubhead()returnself.data.subheadendfunctionArticle:getFragment()localfragment=self:getMatchedTags()[1]iffragmentthenreturnmw.uri.anchorEncode(fragment)endendfunctionArticle:getFullPage()localpage=self:getPage()localfragment=self:getFragment()iffragmentthenreturnpage..'#'..fragmentelsereturnpageendendfunctionArticle:addMatchedTag(tag)table.insert(self.matchedTags,tag)endfunctionArticle:getMatchedTags()table.sort(self.matchedTags)returnself.matchedTagsendfunctionArticle:hasAllTags(t)localtags=self.data.tagsfori,testTaginipairs(t)dolocalhasTag=falseforj,taginipairs(tags)doiftag==testTagthenhasTag=trueendendifnothasTagthenreturnfalseendendreturntrueendfunctionArticle:makeRowArgs()localmethods=self.rowMethodslocalargs=setmetatable({},{__index=function(t,key)localmethod=methods[key]ifmethodthenreturnself[method](self)elseerror(string.format("'%s' is not a valid parameter name",key),2)endend})returnargsendfunctionArticle:renderTemplate(template,frame)frame=frameormw.getCurrentFrame()localargs={}forkey,methodinpairs(self.rowMethods)doargs[key]=self[method](self)endreturnframe:expandTemplate{title=template,args=args}endfunctionArticle:renderFormat(format)localargs=self:makeRowArgs(articleObj)localret=format:gsub('(%${([%a%d]+)})',function(match,key)returnargs[key]ormatchend)returnretend---------------------------------------------------------------------------------- List class--------------------------------------------------------------------------------localList={}List.__index=ListfunctionList.new(options)checkType('List.new',1,options,'table')checkTypeForNamedArg('List.new','args',options.args,'table',true)localself=setmetatable({},List)self.index=options.indexormw.loadData(INDEX_MODULE)self.frame=options.frameormw.getCurrentFrame()localargs=options.argsor{}-- Set output formatsifnotoptions.suppressFormatErrorsandargs.rowtemplateandargs.rowformatthenerror("you cannot use both the 'rowtemplate' and the 'rowformat' arguments",2)elseifnotoptions.suppressFormatErrorsandnotargs.rowtemplateandnotargs.rowformatthenerror("you must use either the 'rowtemplate' or the 'rowformat' argument",2)elseself.rowtemplate=args.rowtemplateself.rowformat=args.rowformatendifargs.rowseparator=='newline'thenself.rowseparator='\n'elseself.rowseparator=args.rowseparatorendself.noarticles=args.noarticles-- Get article objects, filtered by page, date and tag, and sort them.ifargs.pagethenself.articles={self:getPageArticle(args.page)}elseifargs.datethenself.articles=self:getDateArticles(args.date)elseself.articles=self:getTagArticles(args.tags,args.tagmatch)ifnotself.articlesthenself.articles=self:getAllArticles()endself:filterArticlesByDate(args.startdate,args.enddate)self:filterArticlesByAuthor(args.author)endself:sortArticles(args.sortdir,args.sortfield)if(args.limitandtonumber(args.limit))or(args.startandtonumber(args.start))thenself:limitArticleCount(tonumber(args.start),tonumber(args.limit))endreturnselfend-- Static methodsfunctionList.normalizeDate(date)ifnotdatethenreturnnilendreturnlang:formatDate('Y-m-d',date)end-- Normal methodsfunctionList:parseTagString(s)localret={}-- Remove whitespace and punctuationfori,taginipairs(mw.text.split(s,','))dotag=mw.ustring.gsub(tag,'[%s%p]','')iftag~=''thentag=mw.ustring.lower(tag)table.insert(ret,tag)endend-- Resolve aliasesfori,taginipairs(ret)doret[i]=self.index.aliases[tag]ortagend-- Remove duplicateslocalfunctionremoveDuplicates(t)localvals,ret={},{}fori,valinipairs(t)dovals[val]=trueendforvalinpairs(vals)dotable.insert(ret,val)endtable.sort(ret)returnretendret=removeDuplicates(ret)returnretendfunctionList:getPageArticle(page)localdata=self.index.pages[page]ifdatathenreturnArticle.new(data)endendfunctionList:getDateArticles(date)date=self.normalizeDate(date)localdates=self.index.dates[date]localret={}ifdatesthenfori,datainipairs(dates)doret[i]=Article.new(data)endendreturnretendfunctionList:getTagArticles(s,tagMatch)ifnotsthenreturnnilendlocaltagIndex=self.index.tagslocalret,pages={},{}localtags=self:parseTagString(s)fori,taginipairs(tags)dolocaldataArray=tagIndex[tag]ifdataArraythenfori,datainipairs(dataArray)dolocalobj=Article.new(data)-- Make sure we only have one object per page.ifpages[obj:getPage()]thenobj=pages[obj:getPage()]elsepages[obj:getPage()]=objend-- Record which tag we matched.obj:addMatchedTag(tag)endendendforpage,objinpairs(pages)doifnottagMatchortagMatch=='any'ortagMatch=='all'andobj:hasAllTags(tags)thentable.insert(ret,obj)endendreturnretendfunctionList:getAllArticles()localret={}fori,datainipairs(self.index.list)doret[i]=Article.new(data)endreturnretendfunctionList:getArticleCount()return#self.articlesendfunctionList:filterArticlesByDate(startDate,endDate)startDate=self.normalizeDate(startDate)or'2005-01-01'endDate=self.normalizeDate(endDate)orlang:formatDate('Y-m-d')localret={}fori,articleinipairs(self.articles)dolocaldate=article:getDate()ifstartDate<=dateanddate<=endDatethentable.insert(ret,article)endendself.articles=retendfunctionList:filterArticlesByAuthor(targetAuthor)ifnottargetAuthorthenreturnendlocalret={}fori,articleinipairs(self.articles)doforj,authorinipairs(article:getAuthors())doifauthor==targetAuthorthentable.insert(ret,article)endendendself.articles=retendfunctionList:sortArticles(direction,field)localaccessorifnotfieldorfield=='date'thenaccessor=function(article)returnarticle:getSortKey()endelseiffield=='page'thenaccessor=function(article)returnarticle:getPage()endelseiffield=='title'thenaccessor=function(article)returnarticle:getTitle()endelseerror(string.format("'%s' is not a valid sort field",field),2)endlocalsortFuncifnotdirectionordirection=='ascending'thensortFunc=function(a,b)returnaccessor(a)<accessor(b)endelseifdirection=='descending'thensortFunc=function(a,b)returnaccessor(a)>accessor(b)endelseerror(string.format("'%s' is not a valid sort direction",direction),2)endtable.sort(self.articles,sortFunc)endfunctionList:limitArticleCount(start,limit)localret={}fori,articleinipairs(self.articles)doiflimitand#ret>=limitthenbreakendifnotstartori>startthentable.insert(ret,article)endendself.articles=retendfunctionList:renderRow(articleObj)ifself.rowtemplatethenreturnarticleObj:renderTemplate(self.rowtemplate,self.frame)elseifself.rowformatthenreturnarticleObj:renderFormat(self.rowformat)elseerror('neither rowtemplate nor rowformat were specified')endendfunctionList:__tostring()localret={}fori,objinipairs(self.articles)dotable.insert(ret,self:renderRow(obj))endif#ret<1thenreturnself.noarticlesor'<span style="font-color: red;">'..'No articles found for the arguments specified</span>'elsereturntable.concat(ret,self.rowseparator)endend---------------------------------------------------------------------------------- Exports--------------------------------------------------------------------------------localp={}localfunctionmakeInvokeFunc(func)returnfunction(frame,index)localargs=require('Module:Arguments').getArgs(frame,{parentOnly=true})returnfunc(args,index)endendfunctionp._exportClasses()return{Article=Article,List=List}endfunctionp._count(args,index)locallist=List.new{args=args,index=index,suppressFormatErrors=true}returnlist:getArticleCount()endp.count=makeInvokeFunc(p._count)functionp._main(args,index)returntostring(List.new{args=args,index=index})endp.main=makeInvokeFunc(p._main)returnp