Jump to content

Module:Excerpt/sandbox

From Wikipedia, the free encyclopedia
-- Module:Excerpt implements the Excerpt template-- Documentation and master version: https://en.wikipedia.org/wiki/Module:Excerpt-- Authors: User:Sophivorus, User:Certes, User:Aidan9382 & others-- License: CC-BY-SA-3.0localparser=require('Module:WikitextParser')localyesno=require('Module:Yesno')localok,config=pcall(require,'Module:Excerpt/config')ifnotokthenconfig={}endlocalExcerpt={}-- Main entry point for templatesfunctionExcerpt.main(frame)-- Make sure the requested page exists and get the wikitextlocalpage=Excerpt.getArg(1)ifnotpageorpage=='{{{1}}}'thenreturnExcerpt.getError('no-page')endlocaltitle=mw.title.new(page)ifnottitlethenreturnExcerpt.getError('invalid-title',page)endlocalfragment=title.fragment-- save for lateriftitle.isRedirectthentitle=title.redirectTargetendifnottitle.existsthenreturnExcerpt.getError('page-not-found',page)endpage=title.prefixedTextlocalwikitext=title:getContent()-- Get the template params and process themlocalparams={hat=yesno(Excerpt.getArg('hat',true)),this=Excerpt.getArg('this'),only=Excerpt.getArg('only'),files=Excerpt.getArg('files'),lists=Excerpt.getArg('lists'),tables=Excerpt.getArg('tables'),templates=Excerpt.getArg('templates'),paragraphs=Excerpt.getArg('paragraphs'),references=yesno(Excerpt.getArg('references',true)),subsections=yesno(Excerpt.getArg('subsections',false)),links=yesno(Excerpt.getArg('links',true)),bold=yesno(Excerpt.getArg('bold',false)),briefDates=yesno(Excerpt.getArg('briefdates',false)),inline=yesno(Excerpt.getArg('inline')),quote=yesno(Excerpt.getArg('quote')),more=yesno(Excerpt.getArg('more')),class=Excerpt.getArg('class'),displayTitle=Excerpt.getArg('displaytitle',page),}-- Make sure the requested section exists and get the excerptlocalexcerptlocalsection=Excerpt.getArg(2,fragment)section=mw.text.trim(section)ifsection==''thensection=nilendifsectionthenexcerpt=parser.getSectionTag(wikitext,section)ifnotexcerptthenifparams.subsectionsthenexcerpt=parser.getSection(wikitext,section)elselocalsections=parser.getSections(wikitext)excerpt=sections[section]endendifnotexcerptthenreturnExcerpt.getError('section-not-found',section)endifexcerpt==''thenreturnExcerpt.getError('section-empty',section)endelseexcerpt=parser.getLead(wikitext)ifexcerpt==''thenreturnExcerpt.getError('lead-empty')endend-- Filter various elements from the excerptexcerpt=Excerpt.filterFiles(excerpt,params.files)excerpt=Excerpt.filterLists(excerpt,params.lists)excerpt=Excerpt.filterTables(excerpt,params.tables)excerpt=Excerpt.filterParagraphs(excerpt,params.paragraphs)-- If no file is found, try to get one from the infoboxif(params.only=='file'orparams.only=='files'ornotparams.onlyand(notparams.filesorparams.files~='0'))-- caller asked for filesandnotsection-- and we're in the lead sectionandconfig.captions-- and we have the config option required to try finding files in infoboxesand#parser.getFiles(excerpt)==0-- and there're no files in the excerptthenexcerpt=Excerpt.addInfoboxFile(excerpt)end-- Filter the templates by appending the templates blacklist to the templates filterifconfig.blacklistthenlocalblacklist=table.concat(config.blacklist,',')ifparams.templatesthenifstring.sub(params.templates,1,1)=='-'thenparams.templates=params.templates..','..blacklistendelseparams.templates='-'..blacklistendendexcerpt=Excerpt.filterTemplates(excerpt,params.templates)-- Leave only the requested elementsifparams.only=='file'orparams.only=='files'thenlocalfiles=parser.getFiles(excerpt)excerpt=params.only=='file'andfiles[1]ortable.concat(files,'\n\n')endifparams.only=='list'orparams.only=='lists'thenlocallists=parser.getLists(excerpt)excerpt=params.only=='list'andlists[1]ortable.concat(lists,'\n\n')endifparams.only=='table'orparams.only=='tables'thenlocaltables=parser.getTables(excerpt)excerpt=params.only=='table'andtables[1]ortable.concat(tables,'\n\n')endifparams.only=='paragraph'orparams.only=='paragraphs'thenlocalparagraphs=parser.getParagraphs(excerpt)excerpt=params.only=='paragraph'andparagraphs[1]ortable.concat(paragraphs,'\n\n')endifparams.only=='template'orparams.only=='templates'thenlocaltemplates=parser.getTemplates(excerpt)excerpt=params.only=='template'andtemplates[1]ortable.concat(templates,'\n\n')end-- @todo Make more robust and move downwardsifparams.briefDatesthenexcerpt=Excerpt.fixDates(excerpt)end-- Remove unwanted elementsexcerpt=Excerpt.removeComments(excerpt)excerpt=Excerpt.removeSelfLinks(excerpt)excerpt=Excerpt.removeNonFreeFiles(excerpt)excerpt=Excerpt.removeBehaviorSwitches(excerpt)-- Fix or remove the referencesifparams.referencesthenexcerpt=Excerpt.fixReferences(excerpt,page,wikitext)elseexcerpt=Excerpt.removeReferences(excerpt)end-- Remove wikilinksifnotparams.linksthenexcerpt=Excerpt.removeLinks(excerpt)end-- Link the bold text and then remove itexcerpt=Excerpt.linkBold(excerpt,page)ifnotparams.boldthenexcerpt=Excerpt.removeBold(excerpt)end-- Remove extra line breaks but leave one before and after so the parser interprets lists, tables, etc. correctlyexcerpt=string.gsub(excerpt,'\n\n\n+','\n\n')excerpt=mw.text.trim(excerpt)excerpt='\n'..excerpt..'\n'-- Remove nested categoriesexcerpt=frame:preprocess(excerpt)excerpt=Excerpt.removeCategories(excerpt)-- Add tracking categoriesifconfig.categoriesthenexcerpt=Excerpt.addTrackingCategories(excerpt)end-- Build the final outputifparams.inlinethenreturnmw.text.trim(excerpt)endlocaltag=params.quoteand'blockquote'or'div'localblock=mw.html.create(tag):addClass('excerpt-block'):addClass(params.class)ifconfig.stylesthenlocalstyles=frame:extensionTag('templatestyles','',{src=config.styles})block:node(styles)endifparams.hatthenlocalhat=Excerpt.getHat(page,section,params)block:node(hat)endexcerpt=mw.html.create('div'):addClass('excerpt'):wikitext(excerpt)block:node(excerpt)ifparams.morethenlocalmore=Excerpt.getReadMore(page,section)block:node(more)endreturnblockend-- Filter the files in the given wikitext against the given filterfunctionExcerpt.filterFiles(wikitext,filter)ifnotfilterthenreturnwikitextendlocalfilters,isBlacklist=Excerpt.parseFilter(filter)localfiles=parser.getFiles(wikitext)forindex,fileinpairs(files)dolocalname=parser.getFileName(file)ifisBlacklistand(Excerpt.matchFilter(index,filters)orExcerpt.matchFilter(name,filters))ornotisBlacklistand(notExcerpt.matchFilter(index,filters)andnotExcerpt.matchFilter(name,filters))thenwikitext=Excerpt.removeString(wikitext,file)endendreturnwikitextend-- Filter the lists in the given wikitext against the given filterfunctionExcerpt.filterLists(wikitext,filter)ifnotfilterthenreturnwikitextendlocalfilters,isBlacklist=Excerpt.parseFilter(filter)locallists=parser.getLists(wikitext)forindex,listinpairs(lists)doifisBlacklistandExcerpt.matchFilter(index,filters)ornotisBlacklistandnotExcerpt.matchFilter(index,filters)thenwikitext=Excerpt.removeString(wikitext,list)endendreturnwikitextend-- Filter the tables in the given wikitext against the given filterfunctionExcerpt.filterTables(wikitext,filter)ifnotfilterthenreturnwikitextendlocalfilters,isBlacklist=Excerpt.parseFilter(filter)localtables=parser.getTables(wikitext)forindex,tinpairs(tables)dolocalid=string.match(t,'{|[^\n]-id%s*=%s*["\']?([^"\'\n]+)["\']?[^\n]*\n')ifisBlacklistand(Excerpt.matchFilter(index,filters)orExcerpt.matchFilter(id,filters))ornotisBlacklistand(notExcerpt.matchFilter(index,filters)andnotExcerpt.matchFilter(id,filters))thenwikitext=Excerpt.removeString(wikitext,t)endendreturnwikitextend-- Filter the paragraphs in the given wikitext against the given filterfunctionExcerpt.filterParagraphs(wikitext,filter)ifnotfilterthenreturnwikitextendlocalfilters,isBlacklist=Excerpt.parseFilter(filter)localparagraphs=parser.getParagraphs(wikitext)forindex,paragraphinpairs(paragraphs)doifisBlacklistandExcerpt.matchFilter(index,filters)ornotisBlacklistandnotExcerpt.matchFilter(index,filters)thenwikitext=Excerpt.removeString(wikitext,paragraph)endendreturnwikitextend-- Filter the templates in the given wikitext against the given filterfunctionExcerpt.filterTemplates(wikitext,filter)ifnotfilterthenreturnwikitextendlocalfilters,isBlacklist=Excerpt.parseFilter(filter)localtemplates=parser.getTemplates(wikitext)forindex,templateinpairs(templates)dolocalname=parser.getTemplateName(template)ifisBlacklistand(Excerpt.matchFilter(index,filters)orExcerpt.matchFilter(name,filters))ornotisBlacklistand(notExcerpt.matchFilter(index,filters)andnotExcerpt.matchFilter(name,filters))thenwikitext=Excerpt.removeString(wikitext,template)endendreturnwikitextendfunctionExcerpt.addInfoboxFile(excerpt)-- We cannot distinguish the infobox from the other templates, so we search them alllocaltemplates=parser.getTemplates(excerpt)for_,templateinpairs(templates)dolocalparameters=parser.getTemplateParameters(template)localfile,captions,caption,cssClasses,cssClassfor_,pairinpairs(config.captions)dofile=pair[1]file=parameters[file]iffileandExcerpt.matchAny(file,'^.*%.',{'[Jj][Pp][Ee]?[Gg]','[Pp][Nn][Gg]','[Gg][Ii][Ff]','[Ss][Vv][Gg]'},'.*')thenfile=mw.ustring.match(file,'%[?%[?.-:([^{|]+)%]?%]?')orfile-- [[File:Example.jpg{{!}}upright=1.5]] to Example.jpgcaptions=pair[2]for_,pinpairs(captions)doifparameters[p]thencaption=parameters[p]breakendend-- Check for CSS classes-- We opt to use skin-invert-image instead of skin-invert-- in all other cases, the CSS provided in the infobox is usedifpair[3]thencssClasses=pair[3]for_,pinpairs(cssClasses)doifparameters[p]thencssClass=(parameters[p]=='skin-invert')and'skin-invert-image'orparameters[p]breakendendendlocalclass=cssClassand('|class='..cssClass)or''return'[[File:'..file..class..'|thumb|'..(captionor'')..']]'..excerptendendendreturnexcerptendfunctionExcerpt.removeNonFreeFiles(wikitext)localfiles=parser.getFiles(wikitext)for_,fileinpairs(files)dolocalfileName='File:'..parser.getFileName(file)localfileTitle=mw.title.new(fileName)iffileTitlethenlocalfileDescription=fileTitle:getContent()ifnotfileDescriptionorfileDescription==''thenlocalframe=mw.getCurrentFrame()fileDescription=frame:preprocess('{{'..fileName..'}}')-- try CommonsendiffileDescriptionandstring.match(fileDescription,'[Nn]on%-free')thenwikitext=Excerpt.removeString(wikitext,file)endendendreturnwikitextendfunctionExcerpt.getHat(page,section,params)localhat-- Build the textifparams.thisthenhat=params.thiselseifparams.quotethenhat=Excerpt.getMessage('this')elseifparams.onlythenhat=Excerpt.getMessage(params.only)elsehat=Excerpt.getMessage('section')endhat=hat..' '..Excerpt.getMessage('excerpt')-- Build the linkifsectionthenhat=hat..' [[:'..page..'#'..mw.uri.anchorEncode(section)..'|'..params.displayTitle..' § '..mw.ustring.gsub(section,'%[%[([^]|]+)|?[^]]*%]%]','%1')..']].'-- remove nested linkselsehat=hat..' [[:'..page..'|'..params.displayTitle..']].'end-- Build the edit linklocaltitle=mw.title.new(page)localeditUrl=title:fullUrl('action=edit')hat=hat..'<span class="mw-editsection-like plainlinks"><span class="mw-editsection-bracket">[</span>['hat=hat..editUrl..' '..mw.message.new('editsection'):plain()hat=hat..']<span class="mw-editsection-bracket">]</span></span>'ifconfig.hatthenlocalframe=mw.getCurrentFrame()hat=config.hat..hat..'}}'hat=frame:preprocess(hat)elsehat=mw.html.create('div'):addClass('dablink excerpt-hat'):wikitext(hat)endreturnhatendfunctionExcerpt.getReadMore(page,section)locallink="'''[["..pageifsectionthenlink=link..'#'..sectionendlocaltext=Excerpt.getMessage('more')link=link..'|'..text.."]]'''"link=mw.html.create('div'):addClass('noprint excerpt-more'):wikitext(link)returnlinkend-- Fix birth and death dates, but only in the first paragraph-- @todo Use parser.getParagraphs() to get the first paragraphfunctionExcerpt.fixDates(excerpt)localstartpos=1-- skip initial templateslocalslocale=0repeatstartpos=e+1s,e=mw.ustring.find(excerpt,"%s*%b{}%s*",startpos)untilnotsors>startposs,e=mw.ustring.find(excerpt,"%b()",startpos)-- get (...), which may be (year–year)ifsands<startpos+100then-- look only near the startlocalyear1,conjunction,year2=mw.ustring.match(mw.ustring.sub(excerpt,s,e),'(%d%d%d+)(.-)(%d%d%d+)')ifyear1andyear2and(mw.ustring.match(conjunction,'[%-–—]')ormw.ustring.match(conjunction,'{{%s*[sS]nd%s*}}'))thenlocaly1=tonumber(year1)localy2=tonumber(year2)ify2>y1andy2<y1+125andy1<=tonumber(os.date("%Y"))thenexcerpt=mw.ustring.sub(excerpt,1,s)..year1.."–"..year2..mw.ustring.sub(excerpt,e)endendendreturnexcerptend-- Replace the first call to each reference defined outside of the excerpt for the full reference, to prevent undefined references-- Then prefix the page title to the reference names to prevent conflicts-- that is, replace <ref name="Foo"> for <ref name="Title of the article Foo">-- and also <ref name="Foo" /> for <ref name="Title of the article Foo" />-- also remove reference groups: <ref name="Foo" group="Bar"> for <ref name="Title of the article Foo">-- and <ref group="Bar"> for <ref>-- @todo The current regex may fail in cases with both kinds of quotes, like <ref name="Darwin's book">functionExcerpt.fixReferences(excerpt,page,wikitext)localreferences=parser.getReferences(excerpt)localfixed={}for_,referenceinpairs(references)dolocalname=parser.getTagAttribute(reference,'name')ifnotfixed[name]thenlocalcontent=parser.getTagContent(reference)ifnotcontentthen-- reference is self-closinglocalfull=parser.getReference(excerpt,name)ifnotfullthen-- the reference is not defined in the excerptfull=parser.getReference(wikitext,name)table.insert(fixed,name)-- search each reference only onceiffullthenexcerpt:gsub(Excerpt.escapeString(reference),main,1)endendendendend-- Prepend the page title to the reference names to prevent conflicts with other references in the transcluding pageexcerpt=excerpt:gsub('< *[Rr][Ee][Ff][^>]*name *= *["\']?([^"\'>/]+)["\']?[^>/]*(/?) *>','<ref name="'..page:gsub('"','')..' %1"%2>')-- Remove reference groups because they don't apply to the transcluding pageexcerpt=excerpt:gsub('< *[Rr][Ee][Ff] *group *= *["\']?[^"\'>/]+["\'] *>','<ref>')returnexcerptendfunctionExcerpt.removeReferences(excerpt)localreferences=parser.getReferences(excerpt)for_,referenceinpairs(references)doexcerpt=Excerpt.removeString(excerpt,reference)endreturnexcerptendfunctionExcerpt.removeCategories(excerpt)localcategories=parser.getCategories(excerpt)for_,categoryinpairs(categories)doexcerpt=Excerpt.removeString(excerpt,category)endreturnexcerptendfunctionExcerpt.removeBehaviorSwitches(excerpt)returnstring.gsub(excerpt,'__[A-Z]+__','')endfunctionExcerpt.removeComments(excerpt)returnstring.gsub(excerpt,'<!%-%-.-%-%->','')endfunctionExcerpt.removeBold(excerpt)returnstring.gsub(excerpt,"'''",'')endfunctionExcerpt.removeLinks(excerpt)locallinks=parser.getLinks(excerpt)for_,linkinpairs(links)doexcerpt=Excerpt.removeString(excerpt,link)endreturnexcerptend-- @todo Use parser.getLinksfunctionExcerpt.removeSelfLinks(excerpt,page)locallang=mw.language.getContentLanguage()localpage=Excerpt.escapeString(mw.title.getCurrentTitle().prefixedText)localucpage=lang:ucfirst(page)locallcpage=lang:lcfirst(page)excerpt=excerpt:gsub('%[%[('..ucpage..')%]%]','%1'):gsub('%[%[('..lcpage..')%]%]','%1'):gsub('%[%['..ucpage..'|([^]]+)%]%]','%1'):gsub('%[%['..lcpage..'|([^]]+)%]%]','%1')returnexcerptend-- Replace the bold title or synonym near the start of the page by a link to the pagefunctionExcerpt.linkBold(excerpt,page)locallang=mw.language.getContentLanguage()localposition=mw.ustring.find(excerpt,"'''"..lang:ucfirst(page).."'''",1,true)-- look for "'''Foo''' is..." (uc) or "A '''foo''' is..." (lc)ormw.ustring.find(excerpt,"'''"..lang:lcfirst(page).."'''",1,true)-- plain search: special characters in page represent themselvesifpositionthenlocallength=mw.ustring.len(page)excerpt=mw.ustring.sub(excerpt,1,position+2)..'[['..mw.ustring.sub(excerpt,position+3,position+length+2)..']]'..mw.ustring.sub(excerpt,position+length+3,-1)-- link itelse-- look for anything unlinked in bold, assumed to be a synonym of the title (e.g. a person's birth name)excerpt=mw.ustring.gsub(excerpt,"()'''(.-'*)'''",function(a,b)ifnotmw.ustring.find(b,'%[')andnotmw.ustring.find(b,'%{')then-- if not wikilinked or some weird templatereturn"'''[["..page..'|'..b.."]]'''"-- replace '''Foo''' by '''[[page|Foo]]'''elsereturnnil-- instruct gsub to make no changeendend,1)-- "end" here terminates the anonymous replacement function(a, b) passed to gsubendreturnexcerptendfunctionExcerpt.addTrackingCategories(excerpt)localcurrentTitle=mw.title.getCurrentTitle()localcontentCategory=config.categories.contentifcontentCategoryandcurrentTitle.isContentPagethenexcerpt=excerpt..'[[Category:'..contentCategory..']]'endlocalnamespaceCategory=config.categories[currentTitle.namespace]ifnamespaceCategorythenexcerpt=excerpt..'[[Category:'..namespaceCategory..']]'endreturnexcerptend-- Helper method to match from a list of regular expressions-- Like so: match pre..list[1]..post or pre..list[2]..post or ...functionExcerpt.matchAny(text,pre,list,post,init)localmatch={}fori=1,#listdomatch={mw.ustring.match(text,pre..list[i]..post,init)}ifmatch[1]thenreturnunpack(match)endendreturnnilend-- Helper function to get arguments-- args from Lua calls have priority over parent args from templatefunctionExcerpt.getArg(key,default)localframe=mw.getCurrentFrame()fork,valueinpairs(frame:getParent().args)doifk==keyandmw.text.trim(value)~=''thenreturnvalueendendfork,valueinpairs(frame.args)doifk==keyandmw.text.trim(value)~=''thenreturnvalueendendreturndefaultend-- Helper method to get an error message-- This method also categorizes the current page in one of the configured error categoriesfunctionExcerpt.getError(key,value)localmessage=Excerpt.getMessage('error-'..key,value)localmarkup=mw.html.create('div'):addClass('error'):wikitext(message)ifconfig.categoriesandconfig.categories.errorsandmw.title.getCurrentTitle().isContentPagethenmarkup:node('[[Category:'..config.categories.errors..']]')endreturnmarkupend-- Helper method to get a localized message-- This method uses Module:TNT to get localized messages from https://commons.wikimedia.org/wiki/Data:I18n/Module:Excerpt.tab-- If Module:TNT is not available or the localized message does not exist, the key is returned insteadfunctionExcerpt.getMessage(key,value)localok,TNT=pcall(require,'Module:TNT')ifnotokthenreturnkeyendlocalok2,message=pcall(TNT.format,'I18n/Module:Excerpt.tab',key,value)ifnotok2thenreturnkeyendreturnmessageend-- Helper method to escape a string for use in regexesfunctionExcerpt.escapeString(str)returnstr:gsub('[%^%$%(%)%.%[%]%*%+%-%?%%]','%%%0')end-- Helper method to remove a string from a text-- @param text Text from where to remove the string-- @param str String to remove-- @return The given text with the string removedfunctionExcerpt.removeString(text,str)localpattern=Excerpt.escapeString(str)if#pattern>9999then-- strings longer than 10000 bytes can't be put into regexespattern=Excerpt.escapeString(mw.ustring.sub(str,1,999))..'.-'..Excerpt.escapeString(mw.ustring.sub(str,-999))endreturnstring.gsub(text,pattern,'')end-- Helper method to convert a comma-separated list of numbers or min-max ranges into a list of booleans-- @param filter Required. Comma-separated list of numbers or min-max ranges, for example '1,3-5'-- @return Map from integers to booleans, for example {1=true,2=false,3=true,4=true,5=true}-- @return Boolean indicating whether the filters should be treated as a blacklist or not-- @note Merging this into matchFilter is possible, but way too inefficientfunctionExcerpt.parseFilter(filter)localfilters={}localisBlacklist=falseifstring.sub(filter,1,1)=='-'thenisBlacklist=truefilter=string.sub(filter,2)endlocalvalues=mw.text.split(filter,',')-- split values: '1,3-5' to {'1','3-5'}for_,valueinpairs(values)dovalue=mw.text.trim(value)localmin,max=mw.ustring.match(value,'^(%d+)%s*[-–—]%s*(%d+)$')-- '3-5' to min=3 max=5ifnotmaxthenmin,max=string.match(value,'^((%d+))$')end-- '1' to min=1 max=1ifmaxthenfori=min,maxdofilters[i]=trueendelsefilters[value]=true-- if we reach this point, the string had the form 'a,b,c' rather than '1,2,3'endendreturnfilters,isBlacklistend-- Helper function to see if a value matches any of the given filtersfunctionExcerpt.matchFilter(value,filters)value=tostring(value)locallang=mw.language.getContentLanguage()locallcvalue=lang:lcfirst(value)localucvalue=lang:ucfirst(value)forfilterinpairs(filters)dofilter=tostring(filter)ifvalue==filterorlcvalue==filterorucvalue==filterormw.ustring.match(value,filter)thenreturntrueendendend-- Entry points for backwards compatibility-- @todo Verify that no one uses them and remove themfunctionExcerpt.lead(frame)returnExcerpt.main(frame)endfunctionExcerpt.excerpt(frame)returnExcerpt.main(frame)endreturnExcerpt
close