Module:Citation/CS1

localz={error_categories={};error_ids={};message_tail={};}-- Include translation message hooks, ID and error handling configuration settings.localcfg=mw.loadData('Module:Citation/CS1/Configuration');-- Contains a list of all recognized parameterslocalwhitelist=mw.loadData('Module:Citation/CS1/Whitelist');-- Whether variable is set or notfunctionis_set(var)returnnot(var==nilorvar=='');end-- First set variable or nil if nonefunctionfirst_set(...)locallist={...};for_,varinpairs(list)doifis_set(var)thenreturnvar;endendend-- Whether needle is in haystackfunctioninArray(needle,haystack)ifneedle==nilthenreturnfalse;endforn,vinipairs(haystack)doifv==needlethenreturnn;endendreturnfalse;end-- Populates numbered arguments in a message string using an argument table.functionsubstitute(msg,args)returnargsandtostring(mw.message.newRawMessage(msg,args))ormsg;end-- Wraps a string using a message_list configuration taking one argumentfunctionwrap(key,str,lower)ifnotis_set(str)thenreturn"";elseifinArray(key,{'italic-title','trans-italic-title'})thenstr=safeforitalics(str);endiflower==truethenreturnsubstitute(cfg.messages[key]:lower(),{str});elsereturnsubstitute(cfg.messages[key],{str});endend--[[Argument wrapper. This function provides support for argument mapping defined in the configuration file so that multiple namescan be transparently aliased to single internal variable.]]functionargument_wrapper(args)localorigin={};returnsetmetatable({ORIGIN=function(self,k)localdummy=self[k];--force the variable to be loaded.returnorigin[k];end},{__index=function(tbl,k)iforigin[k]~=nilthenreturnnil;endlocalargs,list,v=args,cfg.aliases[k];iftype(list)=='table'thenv,origin[k]=selectone(args,list,'redundant_parameters');iforigin[k]==nilthenorigin[k]='';-- Empty string, not nilendelseiflist~=nilthenv,origin[k]=args[list],list;else-- maybe let through instead of raising an error?-- v, origin[k] = args[k], k;error(cfg.messages['unknown_argument_map']);end-- Empty strings, not nil;ifv==nilthenv=cfg.defaults[k]or'';origin[k]='';endtbl=rawset(tbl,k,v);returnv;end,});end-- Checks that parameter name is valid using the whitelistfunctionvalidate(name)name=tostring(name);-- Normal argumentsifwhitelist.basic_arguments[name]thenreturntrue;end-- Arguments with numbers in themname=name:gsub("%d+","#");ifwhitelist.numbered_arguments[name]thenreturntrue;end-- Not found, argument not supported.returnfalseend-- Formats a comment for error trappingfunctionerrorcomment(content,hidden)returnwrap(hiddenand'hidden-error'or'visible-error',content);end--[[Sets an error condition and returns the appropriate error message. The actual placementof the error message in the output is the responsibility of the calling function.]]functionseterror(error_id,arguments,raw,prefix,suffix)localerror_state=cfg.error_conditions[error_id];prefix=prefixor"";suffix=suffixor"";iferror_state==nilthenerror(cfg.messages['undefined_error']);elseifis_set(error_state.category)thentable.insert(z.error_categories,error_state.category);endlocalmessage=substitute(error_state.message,arguments);message=message.." ([["..cfg.messages['help page link'].."#"..error_state.anchor.."|"..cfg.messages['help page label'].."]])";z.error_ids[error_id]=true;ifinArray(error_id,{'bare_url_missing_title','trans_missing_title'})andz.error_ids['citation_missing_title']thenreturn'',false;endmessage=table.concat({prefix,message,suffix});ifraw==truethenreturnmessage,error_state.hidden;endreturnerrorcomment(message,error_state.hidden);end-- Formats a wiki style external linkfunctionexternallinkid(options)localurl_string=options.id;ifoptions.encode==trueoroptions.encode==nilthenurl_string=mw.uri.encode(url_string);endreturnmw.ustring.format('[[%s|%s]]%s[%s%s%s %s]',options.link,options.label,options.separatoror"&nbsp;",options.prefix,url_string,options.suffixor"",mw.text.nowiki(options.id));end-- Formats a wiki style internal linkfunctioninternallinkid(options)returnmw.ustring.format('[[%s|%s]]%s[[%s%s%s|%s]]',options.link,options.label,options.separatoror"&nbsp;",options.prefix,options.id,options.suffixor"",mw.text.nowiki(options.id));end-- Format an external link with error checkingfunctionexternallink(URL,label,source)localerror_str="";ifnotis_set(label)thenlabel=URL;ifis_set(source)thenerror_str=seterror('bare_url_missing_title',{wrap('parameter',source)},false," ");elseerror(cfg.messages["bare_url_no_origin"]);endendifnotcheckurl(URL)thenerror_str=seterror('bad_url',{},false," ")..error_str;endreturntable.concat({"[",URL," ",safeforurl(label),"]",error_str});end-- Formats a link to Amazonfunctionamazon(id,domain)ifnotis_set(domain)thendomain="com"elseif("jp"==domainor"uk"==domain)thendomain="co."..domainendlocalhandler=cfg.id_handlers['ASIN'];returnexternallinkid({link=handler.link,label=handler.label,prefix="//www.amazon."..domain.."/dp/",id=id,encode=handler.encode,separator=handler.separator})end-- Formats a DOI and checks for DOI errors.functiondoi(id,inactive)localcat=""localhandler=cfg.id_handlers['DOI'];localtext;ifis_set(inactive)thentext="[["..handler.link.."|"..handler.label.."]]:"..id;table.insert(z.error_categories,"Pages with DOIs inactive since "..selectyear(inactive));inactive=" ("..cfg.messages['inactive'].." "..inactive..")"elsetext=externallinkid({link=handler.link,label=handler.label,prefix=handler.prefix,id=id,separator=handler.separator,encode=handler.encode})inactive=""endif(string.sub(id,1,3)~="10.")thencat=seterror('bad_doi');endreturntext..inactive..catend-- Formats an OpenLibrary link, and checks for associated errors.functionopenlibrary(id)localcode=id:sub(-1,-1)localhandler=cfg.id_handlers['OL'];if(code=="A")thenreturnexternallinkid({link=handler.link,label=handler.label,prefix="http://openlibrary.org/authors/OL",id=id,separator=handler.separator,encode=handler.encode})elseif(code=="M")thenreturnexternallinkid({link=handler.link,label=handler.label,prefix="http://openlibrary.org/books/OL",id=id,separator=handler.separator,encode=handler.encode})elseif(code=="W")thenreturnexternallinkid({link=handler.link,label=handler.label,prefix="http://openlibrary.org/works/OL",id=id,separator=handler.separator,encode=handler.encode})elsereturnexternallinkid({link=handler.link,label=handler.label,prefix="http://openlibrary.org/OL",id=id,separator=handler.separator,encode=handler.encode})..' '..seterror('bad_ol');endend--[[Determines whether an URL string is validAt present the only check is whether the string appears to be prefixed with a URI scheme. It is not determined whether the URI scheme is valid or whether the URL is otherwise well formed.]]functioncheckurl(url_str)-- Protocol-relative or URL schemereturnurl_str:sub(1,2)=="//"orurl_str:match("^[^/]*:")~=nil;end-- Removes irrelevant text and dashes from ISBN number-- Similar to that used for Special:BookSourcesfunctioncleanisbn(isbn_str)returnisbn_str:gsub("[^-0-9X]","");end-- Determines whether an ISBN string is validfunctioncheckisbn(isbn_str)isbn_str=cleanisbn(isbn_str):gsub("-","");locallen=isbn_str:len();iflen~=10andlen~=13thenreturnfalse;endlocaltemp=0;iflen==10thenifisbn_str:match("^%d*X?$")==nilthenreturnfalse;endisbn_str={isbn_str:byte(1,len)};fori,vinipairs(isbn_str)doifv==string.byte("X")thentemp=temp+10*(11-i);elsetemp=temp+tonumber(string.char(v))*(11-i);endendreturntemp%11==0;elseifisbn_str:match("^%d*$")==nilthenreturnfalse;endisbn_str={isbn_str:byte(1,len)};fori,vinipairs(isbn_str)dotemp=temp+(3-2*(i%2))*tonumber(string.char(v));endreturntemp%10==0;endend-- Gets the display text for a wikilink like [[A|B]] or [[B]] gives Bfunctionremovewikilink(str)return(str:gsub("%[%[([^%[%]]*)%]%]",function(l)returnl:gsub("^[^|]*|(.*)$","%1"):gsub("^%s*(.-)%s*$","%1");end));end-- Escape sequences for content that will be used for URL descriptionsfunctionsafeforurl(str)ifstr:match("%[%[.-%]%]")~=nilthentable.insert(z.message_tail,{seterror('wikilink_in_url',{},true)});endreturnstr:gsub('[%[%]\n]',{['[']='&#91;',[']']='&#93;',['\n']=' '});end-- Converts a hyphen to a dashfunctionhyphentodash(str)ifnotis_set(str)orstr:match("[%[%]{}<>]")~=nilthenreturnstr;endreturnstr:gsub('-','–');end-- Protects a string that will be wrapped in wiki italic markup '' ... ''functionsafeforitalics(str)--[[ Note: We can not use <i> for italics, as the expected behavior for italics specified by ''...'' in the title is that they will be inverted (i.e. unitalicized) in the resulting references. In addition, <i> and '' tend to interact poorly under Mediawiki's HTML tidy. ]]ifnotis_set(str)thenreturnstr;elseifstr:sub(1,1)=="'"thenstr="<span />"..str;endifstr:sub(-1,-1)=="'"thenstr=str.."<span />";end-- Remove newlines as they break italics.returnstr:gsub('\n',' ');endend--[[Joins a sequence of strings together while checking for duplicate separationcharacters.]]functionsafejoin(tbl,duplicate_char)--[[ Note: we use string functions here, rather than ustring functions. This has considerably faster performance and should work correctly as long as the duplicate_char is strict ASCII. The strings in tbl may be ASCII or UTF8. ]]localstr='';localcomp='';localend_chr='';localtrim;for_,valueinipairs(tbl)doifvalue==nilthenvalue='';endifstr==''thenstr=value;elseifvalue~=''thenifvalue:sub(1,1)=='<'then-- Special case of values enclosed in spans and other markup.comp=value:gsub("%b<>","");elsecomp=value;endifcomp:sub(1,1)==duplicate_charthentrim=false;end_chr=str:sub(-1,-1);-- str = str .. "<HERE(enchr=" .. end_chr.. ")"ifend_chr==duplicate_charthenstr=str:sub(1,-2);elseifend_chr=="'"thenifstr:sub(-3,-1)==duplicate_char.."''"thenstr=str:sub(1,-4).."''";elseifstr:sub(-5,-1)==duplicate_char.."]]''"thentrim=true;elseifstr:sub(-4,-1)==duplicate_char.."]''"thentrim=true;endelseifend_chr=="]"thenifstr:sub(-3,-1)==duplicate_char.."]]"thentrim=true;elseifstr:sub(-2,-1)==duplicate_char.."]"thentrim=true;endelseifend_chr==" "thenifstr:sub(-2,-1)==duplicate_char.." "thenstr=str:sub(1,-3);endendiftrimthenifvalue~=compthenlocaldup2=duplicate_char;ifdup2:match("%A")thendup2="%"..dup2;endvalue=value:gsub("(%b<>)"..dup2,"%1",1)elsevalue=value:sub(2,-1);endendendstr=str..value;endendreturnstr;end--[[Return the year portion of a date string, if possible. Returns empty string if the argument can not be interpretedas a year.]]functionselectyear(str)-- Is the input a simple number?localnum=tonumber(str);ifnum~=nilandnum>0andnum<2100andnum==math.floor(num)thenreturnstr;else-- Use formatDate to interpret more complicated formatslocallang=mw.getContentLanguage();localgood,result;good,result=pcall(lang.formatDate,lang,'Y',str)ifgoodthenreturnresult;else-- Can't make sense of this input, return blank.return"";endendend-- Attempts to convert names to initials.functionreducetoinitials(first)localinitials={}forwordinstring.gmatch(first,"%S+")dotable.insert(initials,string.sub(word,1,1))-- Vancouver format does not include full stops.endreturntable.concat(initials)-- Vancouver format does not include spaces.end-- Formats a list of people (e.g. authors / editors) functionlistpeople(control,people)localsep=control.sep;localnamesep=control.nameseplocalformat=control.formatlocalmaximum=control.maximumlocallastauthoramp=control.lastauthoramp;localtext={}localetal=false;ifsep:sub(-1,-1)~=" "thensep=sep.." "endifmaximum~=nilandmaximum<1thenreturn"",0;endfori,personinipairs(people)doifis_set(person.last)thenlocalmask=person.masklocalonelocalsep_one=sep;ifmaximum~=nilandi>maximumthenetal=true;break;elseif(mask~=nil)thenlocaln=tonumber(mask)if(n~=nil)thenone=string.rep("&mdash;",n)elseone=mask;sep_one=" ";endelseone=person.lastlocalfirst=person.firstifis_set(first)thenif("vanc"==format)thenfirst=reducetoinitials(first)endone=one..namesep..firstendifis_set(person.link)thenone="[["..person.link.."|"..one.."]]"endendtable.insert(text,one)table.insert(text,sep_one)endendlocalcount=#text/2;ifcount>0thenifcount>1andis_set(lastauthoramp)andnotetalthentext[#text-2]=" & ";endtext[#text]=nil;endlocalresult=table.concat(text)-- construct listifetalthenlocaletal_text=cfg.messages['et al'];result=result.." "..etal_text;end-- if necessary wrap result in <span> tag to format in Small Capsif("scap"==format)thenresult='<span class="smallcaps" style="font-variant:small-caps">'..result..'</span>';endreturnresult,countend-- Generates a CITEREF anchor ID.functionanchorid(options)return"CITEREF"..table.concat(options);end-- Gets name list from the input argumentsfunctionextractnames(args,list_name)localnames={};locali=1;locallast;whiletruedolast=selectone(args,cfg.aliases[list_name..'-Last'],'redundant_parameters',i);ifnotis_set(last)then-- just in case someone passed in an empty parameterbreak;endnames[i]={last=last,first=selectone(args,cfg.aliases[list_name..'-First'],'redundant_parameters',i),link=selectone(args,cfg.aliases[list_name..'-Link'],'redundant_parameters',i),mask=selectone(args,cfg.aliases[list_name..'-Mask'],'redundant_parameters',i)};i=i+1;endreturnnames;end-- Populates ID table from arguments using configuration settingsfunctionextractids(args)localid_list={};fork,vinpairs(cfg.id_handlers)dov=selectone(args,v.parameters,'redundant_parameters');ifis_set(v)thenid_list[k]=v;endendreturnid_list;end-- Takes a table of IDs and turns it into a table of formatted ID outputs.functionbuildidlist(id_list,options)localnew_list,handler={};functionfallback(k)return{__index=function(t,i)returncfg.id_handlers[k][i]end}end;fork,vinpairs(id_list)do-- fallback to read-only cfghandler=setmetatable({['id']=v},fallback(k));ifhandler.mode=='external'thentable.insert(new_list,{handler.label,externallinkid(handler)});elseifhandler.mode=='internal'thentable.insert(new_list,{handler.label,internallinkid(handler)});elseifhandler.mode~='manual'thenerror(cfg.messages['unknown_ID_mode']);elseifk=='DOI'thentable.insert(new_list,{handler.label,doi(v,options.DoiBroken)});elseifk=='ASIN'thentable.insert(new_list,{handler.label,amazon(v,options.ASINTLD)});elseifk=='OL'thentable.insert(new_list,{handler.label,openlibrary(v)});elseifk=='ISBN'thenlocalISBN=internallinkid(handler);ifnotcheckisbn(v)andnotis_set(options.IgnoreISBN)thenISBN=ISBN..seterror('bad_isbn',{},false," ","");endtable.insert(new_list,{handler.label,ISBN});elseerror(cfg.messages['unknown_manual_ID']);endendfunctioncomp(a,b)returna[1]<b[1];endtable.sort(new_list,comp);fork,vinipairs(new_list)donew_list[k]=v[2];endreturnnew_list;end-- Chooses one matching parameter from a list of parameters to consider-- Generates an error if more than one match is present.functionselectone(args,possible,error_condition,index)localvalue=nil;localselected='';localerror_list={};ifindex~=nilthenindex=tostring(index);end-- Handle special case of "#" replaced by empty stringifindex=='1'thenfor_,vinipairs(possible)dov=v:gsub("#","");ifis_set(args[v])thenifvalue~=nilandselected~=vthentable.insert(error_list,v);elsevalue=args[v];selected=v;endendendendfor_,vinipairs(possible)doifindex~=nilthenv=v:gsub("#",index);endifis_set(args[v])thenifvalue~=nilandselected~=vthentable.insert(error_list,v);elsevalue=args[v];selected=v;endendendif#error_list>0thenlocalerror_str="";for_,kinipairs(error_list)doiferror_str~=""thenerror_str=error_str..cfg.messages['parameter-separator']enderror_str=error_str..wrap('parameter',k);endif#error_list>1thenerror_str=error_str..cfg.messages['parameter-final-separator'];elseerror_str=error_str..cfg.messages['parameter-pair-separator'];enderror_str=error_str..wrap('parameter',selected);table.insert(z.message_tail,{seterror(error_condition,{error_str},true)});endreturnvalue,selected;end-- COinS metadata (see <http://ocoins.info/>) allows automated tools to parse-- the citation information.functionCOinS(data)if'table'~=type(data)ornil==next(data)thenreturn'';endlocalctx_ver="Z39.88-2004";-- treat table strictly as an array with only set values.localOCinSoutput=setmetatable({},{__newindex=function(self,key,value)ifis_set(value)thenrawset(self,#self+1,table.concat{key,'=',mw.uri.encode(removewikilink(value))});endend});ifis_set(data.Chapter)thenOCinSoutput.rft_val_fmt="info:ofi/fmt:kev:mtx:book";OCinSoutput["rft.genre"]="bookitem";OCinSoutput["rft.btitle"]=data.Chapter;OCinSoutput["rft.atitle"]=data.Title;elseifis_set(data.Periodical)thenOCinSoutput.rft_val_fmt="info:ofi/fmt:kev:mtx:journal";OCinSoutput["rft.genre"]="article";OCinSoutput["rft.jtitle"]=data.Periodical;OCinSoutput["rft.atitle"]=data.Title;elseOCinSoutput.rft_val_fmt="info:ofi/fmt:kev:mtx:book";OCinSoutput["rft.genre"]="book"OCinSoutput["rft.btitle"]=data.Title;endOCinSoutput["rft.place"]=data.PublicationPlace;OCinSoutput["rft.date"]=data.Date;OCinSoutput["rft.series"]=data.Series;OCinSoutput["rft.volume"]=data.Volume;OCinSoutput["rft.issue"]=data.Issue;OCinSoutput["rft.pages"]=data.Pages;OCinSoutput["rft.edition"]=data.Edition;OCinSoutput["rft.pub"]=data.PublisherName;fork,vinpairs(data.ID_list)dolocalid,value=cfg.id_handlers[k].COinS;ifk=='ISBN'thenvalue=cleanisbn(v);elsevalue=v;endifstring.sub(idor"",1,4)=='info'thenOCinSoutput["rft_id"]=table.concat{id,"/",v};elseOCinSoutput[id]=value;endendlocallast,first;fork,vinipairs(data.Authors)dolast,first=v.last,v.first;ifk==1thenifis_set(last)thenOCinSoutput["rft.aulast"]=last;endifis_set(first)thenOCinSoutput["rft.aufirst"]=first;endendifis_set(last)andis_set(first)thenOCinSoutput["rft.au"]=table.concat{last,", ",first};elseifis_set(last)thenOCinSoutput["rft.au"]=last;endendOCinSoutput.rft_id=data.URL;OCinSoutput.rfr_id=table.concat{"info:sid/",mw.site.server:match("[^/]*$"),":",data.RawPage};OCinSoutput=setmetatable(OCinSoutput,nil);-- sort with version string always first, and combine.table.sort(OCinSoutput);table.insert(OCinSoutput,1,"ctx_ver="..ctx_ver);-- such as "Z39.88-2004"returntable.concat(OCinSoutput,"&");end--[[This is the main function foing the majority of the citationformatting.]]functioncitation0(config,args)--[[ Load Input Parameters The argment_wrapper facillitates the mapping of multiple aliases to single internal variable. ]]localA=argument_wrapper(args);localilocalPPrefix=A['PPrefix']localPPPrefix=A['PPPrefix']ifis_set(A['NoPP'])thenPPPrefix=""PPrefix=""end-- Pick out the relevant fields from the arguments. Different citation templates-- define different field names for the same underlying things. localAuthors=A['Authors'];locala=extractnames(args,'AuthorList');localCoauthors=A['Coauthors'];localOthers=A['Others'];localEditors=A['Editors'];locale=extractnames(args,'EditorList');localYear=A['Year'];localPublicationDate=A['PublicationDate'];localOrigYear=A['OrigYear'];localDate=A['Date'];localLayDate=A['LayDate'];------------------------------------------------- Get title datalocalTitle=A['Title'];localBookTitle=A['BookTitle'];localConference=A['Conference'];localTransTitle=A['TransTitle'];localTitleNote=A['TitleNote'];localTitleLink=A['TitleLink'];localChapter=A['Chapter'];localChapterLink=A['ChapterLink'];localTransChapter=A['TransChapter'];localTitleType=A['TitleType'];localArchiveURL=A['ArchiveURL'];localURL=A['URL']localURLorigin=A:ORIGIN('URL');localChapterURL=A['ChapterURL'];localChapterURLorigin=A:ORIGIN('ChapterURL');localConferenceURL=A['ConferenceURL'];localConferenceURLorigin=A:ORIGIN('ConferenceURL');localPeriodical=A['Periodical'];if(config.CitationClass=="encyclopaedia")thenifnotis_set(Chapter)thenifnotis_set(Title)thenTitle=Periodical;Periodical='';elseChapter=TitleTransChapter=TransTitleTitle='';TransTitle='';endendendlocalSeries=A['Series'];localVolume=A['Volume'];localIssue=A['Issue'];localPosition='';localPage,Pages,At,page_type;Page=A['Page'];Pages=hyphentodash(A['Pages']);At=A['At'];ifis_set(Page)thenifis_set(Pages)oris_set(At)thenPage=Page.." "..seterror('extra_pages');Pages='';At='';endelseifis_set(Pages)thenifis_set(At)thenPages=Pages.." "..seterror('extra_pages');At='';endendlocalEdition=A['Edition'];localPublicationPlace=A['PublicationPlace']localPlace=A['Place'];ifnotis_set(PublicationPlace)andis_set(Place)thenPublicationPlace=Place;endifPublicationPlace==PlacethenPlace='';endlocalPublisherName=A['PublisherName'];localRegistrationRequired=A['RegistrationRequired'];localSubscriptionRequired=A['SubscriptionRequired'];localVia=A['Via'];localAccessDate=A['AccessDate'];localArchiveDate=A['ArchiveDate'];localAgency=A['Agency'];localDeadURL=A['DeadURL']localLanguage=A['Language'];localFormat=A['Format'];localRef=A['Ref'];localDoiBroken=A['DoiBroken'];localID=A['ID'];localASINTLD=A['ASINTLD'];localIgnoreISBN=A['IgnoreISBN'];localID_list=extractids(args);localQuote=A['Quote'];localPostScript=A['PostScript'];localLayURL=A['LayURL'];localLaySource=A['LaySource'];localTranscript=A['Transcript'];localTranscriptURL=A['TranscriptURL']localTranscriptURLorigin=A:ORIGIN('TranscriptURL');localsepc=A['Separator'];localLastAuthorAmp=A['LastAuthorAmp'];localno_tracking_cats=A['NoTracking'];localuse_lowercase=(sepc~='.');localthis_page=mw.title.getCurrentTitle();--Also used for COinSifnotis_set(no_tracking_cats)thenfork,vinpairs(cfg.uncategorized_namespaces)doifthis_page.nsText==vthenno_tracking_cats="true";break;endendendif(config.CitationClass=="journal")thenifnotis_set(URL)andis_set(ID_list['PMC'])thenlocalEmbargo=A['Embargo'];ifis_set(Embargo)thenlocallang=mw.getContentLanguage();localgood1,result1,good2,result2;good1,result1=pcall(lang.formatDate,lang,'U',Embargo);good2,result2=pcall(lang.formatDate,lang,'U');ifgood1andgood2andtonumber(result1)<tonumber(result2)thenURL="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC"..ID_list['PMC'];URLorigin=cfg.id_handlers['PMC'].parameters[1];endelseURL="http://www.ncbi.nlm.nih.gov/pmc/articles/PMC"..ID_list['PMC'];URLorigin=cfg.id_handlers['PMC'].parameters[1];endendend-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.-- Account for the oddity that is {{cite conference}}, before generation of COinS data.ifis_set(BookTitle)thenChapter=Title;ChapterLink=TitleLink;TransChapter=TransTitle;Title=BookTitle;TitleLink='';TransTitle='';end-- Account for the oddity that is {{cite episode}}, before generation of COinS data.ifconfig.CitationClass=="episode"thenlocalAirDate=A['AirDate'];localSeriesLink=A['SeriesLink'];localSeason=A['Season'];localSeriesNumber=A['SeriesNumber'];localNetwork=A['Network'];localStation=A['Station'];locals,n={},{};localSep=(first_set(A["SeriesSeparator"],A["Separator"])or"").." ";ifis_set(Issue)thentable.insert(s,cfg.messages["episode"].." "..Issue);Issue='';endifis_set(Season)thentable.insert(s,cfg.messages["season"].." "..Season);endifis_set(SeriesNumber)thentable.insert(s,cfg.messages["series"].." "..SeriesNumber);endifis_set(Network)thentable.insert(n,Network);endifis_set(Station)thentable.insert(n,Station);endDate=DateorAirDate;Chapter=Title;ChapterLink=TitleLink;TransChapter=TransTitle;Title=Series;TitleLink=SeriesLink;TransTitle='';Series=table.concat(s,Sep);ID=table.concat(n,Sep);end-- COinS metadata (see <http://ocoins.info/>) for-- automated parsing of citation information.localOCinSoutput=COinS{['Periodical']=Periodical,['Chapter']=Chapter,['Title']=Title,['PublicationPlace']=PublicationPlace,['Date']=first_set(Date,Year,PublicationDate),['Series']=Series,['Volume']=Volume,['Issue']=Issue,['Pages']=first_set(Page,Pages,At),['Edition']=Edition,['PublisherName']=PublisherName,['URL']=first_set(URL,ChapterURL),['Authors']=a,['ID_list']=ID_list,['RawPage']=this_page.prefixedText,};ifis_set(Periodical)andnotis_set(Chapter)andis_set(Title)thenChapter=Title;ChapterLink=TitleLink;TransChapter=TransTitle;Title='';TitleLink='';TransTitle='';end-- Now perform various field substitutions.-- We also add leading spaces and surrounding markup and punctuation to the-- various parts of the citation, but only when they are non-nil.ifnotis_set(Authors)thenlocalMaximum=tonumber(A['DisplayAuthors']);-- Preserve old-style implicit et al.ifnotis_set(Maximum)and#a==9thenMaximum=8;table.insert(z.message_tail,{seterror('implict_etal_author',{},true)});elseifnotis_set(Maximum)thenMaximum=#a+1;endlocalcontrol={sep=A["AuthorSeparator"].." ",namesep=(first_set(A["AuthorNameSeparator"],A["NameSeparator"])or"").." ",format=A["AuthorFormat"],maximum=Maximum,lastauthoramp=LastAuthorAmp};-- If the coauthor field is also used, prevent ampersand and et al. formatting.ifis_set(Coauthors)thencontrol.lastauthoramp=nil;control.maximum=#a+1;endAuthors=listpeople(control,a)endlocalEditorCountifnotis_set(Editors)thenlocalMaximum=tonumber(A['DisplayEditors']);-- Preserve old-style implicit et al.ifnotis_set(Maximum)and#e==4thenMaximum=3;table.insert(z.message_tail,{seterror('implict_etal_editor',{},true)});elseifnotis_set(Maximum)thenMaximum=#e+1;endlocalcontrol={sep=A["EditorSeparator"].." ",namesep=(first_set(A["EditorNameSeparator"],A["NameSeparator"])or"").." ",format=A['EditorFormat'],maximum=Maximum,lastauthoramp=LastAuthorAmp};Editors,EditorCount=listpeople(control,e);elseEditorCount=1;endlocalCartography="";localScale="";ifconfig.CitationClass=="map"thenifnotis_set(Authors)andis_set(PublisherName)thenAuthors=PublisherName;PublisherName="";endCartography=A['Cartography'];ifis_set(Cartography)thenCartography=sepc.." "..wrap('cartography',Cartography,use_lowercase);endScale=A['Scale'];ifis_set(Scale)thenScale=sepc.." "..Scale;endendifnotis_set(Date)thenDate=Year;ifis_set(Date)thenlocalMonth=A['Month'];ifis_set(Month)thenDate=Month.." "..Date;localDay=A['Day']ifis_set(Day)thenDate=Day.." "..DateendendendendifinArray(PublicationDate,{Date,Year})thenPublicationDate='';endifnotis_set(Date)andis_set(PublicationDate)thenDate=PublicationDate;PublicationDate='';end-- Captures the value for Date prior to adding parens or other textual transformationslocalDateIn=Date;ifnotis_set(URL)andnotis_set(ChapterURL)andnotis_set(ArchiveURL)andnotis_set(ConferenceURL)andnotis_set(TranscriptURL)then-- Test if cite web is called without giving a URLif(config.CitationClass=="web")thentable.insert(z.message_tail,{seterror('cite_web_url',{},true)});end-- Test if accessdate is given without giving a URLifis_set(AccessDate)thentable.insert(z.message_tail,{seterror('accessdate_missing_url',{},true)});AccessDate='';end-- Test if format is given without giving a URLifis_set(Format)thenFormat=Format..seterror('format_missing_url');endend-- Test if citation has no titleifnotis_set(Chapter)andnotis_set(Title)andnotis_set(Periodical)andnotis_set(Conference)andnotis_set(TransTitle)andnotis_set(TransChapter)thentable.insert(z.message_tail,{seterror('citation_missing_title',{},true)});endFormat=is_set(Format)and" ("..Format..")"or"";localOriginalURL=URLDeadURL=DeadURL:lower();ifis_set(ArchiveURL)thenif(DeadURL~="no")thenURL=ArchiveURLURLorigin=A:ORIGIN('ArchiveURL')endend-- Format chapter / article titleifis_set(Chapter)andis_set(ChapterLink)thenChapter="[["..ChapterLink.."|"..Chapter.."]]";endifis_set(Periodical)andis_set(Title)thenChapter=wrap('italic-title',Chapter);TransChapter=wrap('trans-italic-title',TransChapter);elseChapter=wrap('quoted-title',Chapter);TransChapter=wrap('trans-quoted-title',TransChapter);endlocalTransError=""ifis_set(TransChapter)thenifnotis_set(Chapter)thenTransError=" "..seterror('trans_missing_chapter');elseTransChapter=" "..TransChapter;endendChapter=Chapter..TransChapter;ifis_set(Chapter)thenifnotis_set(ChapterLink)thenifis_set(ChapterURL)thenChapter=externallink(ChapterURL,Chapter)..TransError;ifnotis_set(URL)thenChapter=Chapter..Format;Format="";endelseifis_set(URL)thenChapter=externallink(URL,Chapter)..TransError..Format;URL="";Format="";elseChapter=Chapter..TransError;endelseifis_set(ChapterURL)thenChapter=Chapter.." "..externallink(ChapterURL,nil,ChapterURLorigin)..TransError;elseChapter=Chapter..TransError;endChapter=Chapter..sepc.." "-- with end-spaceelseifis_set(ChapterURL)thenChapter=" "..externallink(ChapterURL,nil,ChapterURLorigin)..sepc.." ";end-- Format main title.ifis_set(TitleLink)andis_set(Title)thenTitle="[["..TitleLink.."|"..Title.."]]"endifis_set(Periodical)thenTitle=wrap('quoted-title',Title);TransTitle=wrap('trans-quoted-title',TransTitle);elseifinArray(config.CitationClass,{"web","news","pressrelease","conference"})andnotis_set(Chapter)thenTitle=wrap('quoted-title',Title);TransTitle=wrap('trans-quoted-title',TransTitle);elseTitle=wrap('italic-title',Title);TransTitle=wrap('trans-italic-title',TransTitle);endTransError="";ifis_set(TransTitle)thenifnotis_set(Title)thenTransError=" "..seterror('trans_missing_title');elseTransTitle=" "..TransTitle;endendTitle=Title..TransTitle;ifis_set(Title)thenifnotis_set(TitleLink)andis_set(URL)thenTitle=externallink(URL,Title)..TransError..FormatURL="";Format="";elseTitle=Title..TransError;endendifis_set(Place)thenPlace=" "..wrap('written',Place,use_lowercase)..sepc.." ";endifis_set(Conference)thenifis_set(ConferenceURL)thenConference=externallink(ConferenceURL,Conference);endConference=sepc.." "..Conferenceelseifis_set(ConferenceURL)thenConference=sepc.." "..externallink(ConferenceURL,nil,ConferenceURLorigin);endifnotis_set(Position)thenlocalMinutes=A['Minutes'];ifis_set(Minutes)thenPosition=" "..Minutes.." "..cfg.messages['minutes'];elselocalTime=A['Time'];ifis_set(Time)thenlocalTimeCaption=A['TimeCaption']ifnotis_set(TimeCaption)thenTimeCaption=cfg.messages['event'];ifsepc~='.'thenTimeCaption=TimeCaption:lower();endendPosition=" "..TimeCaption.." "..Time;endendelsePosition=" "..Position;At='';endifnotis_set(Page)thenifis_set(Pages)thenifis_set(Periodical)andnotinArray(config.CitationClass,{"encyclopaedia","web","book","news"})thenPages=": "..Pages;elseiftonumber(Pages)~=nilthenPages=sepc.." "..PPrefix..Pages;elsePages=sepc.." "..PPPrefix..Pages;endendelseifis_set(Periodical)andnotinArray(config.CitationClass,{"encyclopaedia","web","book","news"})thenPage=": "..Page;elsePage=sepc.." "..PPrefix..Page;endendAt=is_set(At)and(sepc.." "..At)or"";Position=is_set(Position)and(sepc.." "..Position)or"";ifconfig.CitationClass=='map'thenlocalSection=A['Section'];localInset=A['Inset'];iffirst_set(Pages,Page,At)~=nilorsepc~='.'thenifis_set(Section)thenSection=", "..wrap('section',Section,true);endifis_set(Inset)thenInset=", "..wrap('inset',Inset,true);endelseifis_set(Section)thenSection=sepc.." "..wrap('section',Section,use_lowercase);ifis_set(Inset)thenInset=", "..wrap('inset',Inset,true);endelseifis_set(Inset)thenInset=sepc.." "..wrap('inset',Inset,use_lowercase);endendAt=At..Section..Inset;endOthers=is_set(Others)and(sepc.." "..Others)or"";TitleType=is_set(TitleType)and(" ("..TitleType..")")or"";TitleNote=is_set(TitleNote)and(sepc.." "..TitleNote)or"";Language=is_set(Language)and(" "..wrap('language',Language))or"";Edition=is_set(Edition)and(" "..wrap('edition',Edition))or"";Issue=is_set(Issue)and(" ("..Issue..")")or"";Series=is_set(Series)and(sepc.." "..Series)or"";OrigYear=is_set(OrigYear)and(" ["..OrigYear.."]")or"";Agency=is_set(Agency)and(sepc.." "..Agency)or"";ifis_set(Volume)thenif(mw.ustring.len(Volume)>4)thenVolume=sepc.." "..Volume;elseVolume=" <b>"..hyphentodash(Volume).."</b>";endend------------------------------------ totally unrelated data-- Mimic {{subscription required}} template; ifis_set(Via)thenVia=" "..wrap('via',Via);end-- SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; --citation always requires subscription if 'via' parameter is used-- This line removed because of editors desire to use via for citations that do not require subscriptionsifis_set(SubscriptionRequired)thenSubscriptionRequired=sepc.." "..cfg.messages['subscription_no_via'];--here when 'via' parameter not used but 'subscription' iselseifis_set(RegistrationRequired)thenSubscriptionRequired=sepc.." "..cfg.messages['registration'];--here when 'via' and 'subscription' parameters not used but 'registration' isendifis_set(AccessDate)thenlocalretrv_text=" "..cfg.messages['retrieved']if(sepc~=".")thenretrv_text=retrv_text:lower()endAccessDate='<span class="reference-accessdate">'..sepc..substitute(retrv_text,{AccessDate})..'</span>'endifis_set(ID)thenID=sepc.." "..ID;endID_list=buildidlist(ID_list,{DoiBroken=DoiBroken,ASINTLD=ASINTLD,IgnoreISBN=IgnoreISBN});ifis_set(URL)thenURL=" "..externallink(URL,nil,URLorigin);endifis_set(Quote)thenifQuote:sub(1,1)=='"'andQuote:sub(-1,-1)=='"'thenQuote=Quote:sub(2,-2);endQuote=sepc.." "..wrap('quoted-text',Quote);PostScript="";elseifPostScript:lower()=="none"thenPostScript="";endlocalArchivedifis_set(ArchiveURL)thenifnotis_set(ArchiveDate)thenArchiveDate=seterror('archive_missing_date');endif"no"==DeadURLthenlocalarch_text=cfg.messages['archived'];ifsepc~="."thenarch_text=arch_text:lower()endArchived=sepc.." "..substitute(cfg.messages['archived-not-dead'],{externallink(ArchiveURL,arch_text),ArchiveDate});ifnotis_set(OriginalURL)thenArchived=Archived.." "..seterror('archive_missing_url');endelseifis_set(OriginalURL)thenlocalarch_text=cfg.messages['archived-dead'];ifsepc~="."thenarch_text=arch_text:lower()endArchived=sepc.." "..substitute(arch_text,{externallink(OriginalURL,cfg.messages['original']),ArchiveDate});elselocalarch_text=cfg.messages['archived-missing'];ifsepc~="."thenarch_text=arch_text:lower()endArchived=sepc.." "..substitute(arch_text,{seterror('archive_missing_url'),ArchiveDate});endelseArchived=""endlocalLayifis_set(LayURL)thenifis_set(LayDate)thenLayDate=" ("..LayDate..")"endifis_set(LaySource)thenLaySource=" &ndash; ''"..safeforitalics(LaySource).."''";elseLaySource="";endifsepc=='.'thenLay=sepc.." "..externallink(LayURL,cfg.messages['lay summary'])..LaySource..LayDateelseLay=sepc.." "..externallink(LayURL,cfg.messages['lay summary']:lower())..LaySource..LayDateendelseLay="";endifis_set(Transcript)thenifis_set(TranscriptURL)thenTranscript=externallink(TranscriptURL,Transcript);endelseifis_set(TranscriptURL)thenTranscript=externallink(TranscriptURL,nil,TranscriptURLorigin);endlocalPublisher;ifis_set(Periodical)andnotinArray(config.CitationClass,{"encyclopaedia","web","pressrelease"})thenifis_set(PublisherName)thenifis_set(PublicationPlace)thenPublisher=PublicationPlace..": "..PublisherName;elsePublisher=PublisherName;endelseifis_set(PublicationPlace)thenPublisher=PublicationPlace;elsePublisher="";endifis_set(PublicationDate)thenifis_set(Publisher)thenPublisher=Publisher..", "..wrap('published',PublicationDate);elsePublisher=PublicationDate;endendifis_set(Publisher)thenPublisher=" ("..Publisher..")";endelseifis_set(PublicationDate)thenPublicationDate=" ("..wrap('published',PublicationDate)..")";endifis_set(PublisherName)thenifis_set(PublicationPlace)thenPublisher=sepc.." "..PublicationPlace..": "..PublisherName..PublicationDate;elsePublisher=sepc.." "..PublisherName..PublicationDate;endelseifis_set(PublicationPlace)thenPublisher=sepc.." "..PublicationPlace..PublicationDate;elsePublisher=PublicationDate;endend-- Several of the above rely upon detecting this as nil, so do it last.ifis_set(Periodical)thenifis_set(Title)oris_set(TitleNote)thenPeriodical=sepc.." "..wrap('italic-title',Periodical)elsePeriodical=wrap('italic-title',Periodical)endend-- Piece all bits together at last. Here, all should be non-nil.-- We build things this way because it is more efficient in LUA-- not to keep reassigning to the same string variable over and over.localtcommonifinArray(config.CitationClass,{"journal","citation"})andis_set(Periodical)thenifis_set(Others)thenOthers=Others..sepc.." "endtcommon=safejoin({Others,Title,TitleNote,Conference,Periodical,Format,TitleType,Scale,Series,Language,Cartography,Edition,Publisher,Agency,Volume,Issue},sepc);elsetcommon=safejoin({Title,TitleNote,Conference,Periodical,Format,TitleType,Scale,Series,Language,Volume,Issue,Others,Cartography,Edition,Publisher,Agency},sepc);endif#ID_list>0thenID_list=safejoin({sepc.." ",table.concat(ID_list,sepc.." "),ID},sepc);elseID_list=ID;endlocalidcommon=safejoin({ID_list,URL,Archived,AccessDate,Via,SubscriptionRequired,Lay,Quote},sepc);localtext;localpgtext=Position..Page..Pages..At;ifis_set(Authors)thenifis_set(Coauthors)thenAuthors=Authors..A['AuthorSeparator'].." "..Coauthorsendifis_set(Date)thenDate=" ("..Date..")"..OrigYear..sepc.." "elseifstring.sub(Authors,-1,-1)==sepcthenAuthors=Authors.." "elseAuthors=Authors..sepc.." "endifis_set(Editors)thenlocalin_text=" ";localpost_text="";ifis_set(Chapter)thenin_text=in_text..cfg.messages['in'].." "elseifEditorCount<=1thenpost_text=", "..cfg.messages['editor'];elsepost_text=", "..cfg.messages['editors'];endendif(sepc~='.')thenin_text=in_text:lower()endEditors=in_text..Editors..post_text;if(string.sub(Editors,-1,-1)==sepc)thenEditors=Editors.." "elseEditors=Editors..sepc.." "endendtext=safejoin({Authors,Date,Chapter,Place,Editors,tcommon},sepc);text=safejoin({text,pgtext,idcommon},sepc);elseifis_set(Editors)thenifis_set(Date)thenifEditorCount<=1thenEditors=Editors..", "..cfg.messages['editor'];elseEditors=Editors..", "..cfg.messages['editors'];endDate=" ("..Date..")"..OrigYear..sepc.." "elseifEditorCount<=1thenEditors=Editors.." ("..cfg.messages['editor']..")"..sepc.." "elseEditors=Editors.." ("..cfg.messages['editors']..")"..sepc.." "endendtext=safejoin({Editors,Date,Chapter,Place,tcommon},sepc);text=safejoin({text,pgtext,idcommon},sepc);elseifis_set(Date)thenif(string.sub(tcommon,-1,-1)~=sepc)thenDate=sepc.." "..Date..OrigYearelseDate=" "..Date..OrigYearendendifconfig.CitationClass=="journal"andis_set(Periodical)thentext=safejoin({Chapter,Place,tcommon},sepc);text=safejoin({text,pgtext,Date,idcommon},sepc);elsetext=safejoin({Chapter,Place,tcommon,Date},sepc);text=safejoin({text,pgtext,idcommon},sepc);endendifis_set(PostScript)andPostScript~=sepcthentext=safejoin({text,sepc},sepc);--Deals with italics, spaces, etc.text=text:sub(1,-2);--Remove final seperator endtext=safejoin({text,PostScript},sepc);-- Now enclose the whole thing in a <span/> elementifnotis_set(Year)thenifis_set(DateIn)thenYear=selectyear(DateIn);elseifis_set(PublicationDate)thenYear=selectyear(PublicationDate);endendlocaloptions={};ifis_set(config.CitationClass)andconfig.CitationClass~="citation"thenoptions.class="citation "..config.CitationClass;elseoptions.class="citation";endifis_set(Ref)andRef:lower()~="none"thenlocalid=Refif("harv"==Ref)thenlocalnames={}--table of last names & yearif#a>0thenfori,vinipairs(a)donames[i]=v.lastifi==4thenbreakendendelseif#e>0thenfori,vinipairs(e)donames[i]=v.lastifi==4thenbreakendendendnames[#names+1]=Year;id=anchorid(names)endoptions.id=id;endifstring.len(text:gsub("<span[^>/]*>.-</span>",""):gsub("%b<>",""))<=2thenz.error_categories={};text=seterror('empty_citation');z.message_tail={};endifis_set(options.id)thentext='<span id="'..mw.uri.anchorEncode(options.id)..'" class="'..mw.text.nowiki(options.class)..'">'..text.."</span>";elsetext='<span class="'..mw.text.nowiki(options.class)..'">'..text.."</span>";endlocalempty_span='<span style="display:none;">&nbsp;</span>';-- Note: Using display: none on then COinS span breaks some clients.localOCinS='<span title="'..OCinSoutput..'" class="Z3988">'..empty_span..'</span>';text=text..OCinS;if#z.message_tail~=0thentext=text.." ";fori,vinipairs(z.message_tail)doifis_set(v[1])thenifi==#z.message_tailthentext=text..errorcomment(v[1],v[2]);elsetext=text..errorcomment(v[1].."; ",v[2]);endendendendno_tracking_cats=no_tracking_cats:lower();ifinArray(no_tracking_cats,{"","no","false","n"})thenfor_,vinipairs(z.error_categories)dotext=text..'[[Category:'..v..']]';endendreturntextend-- This is used by templates such as {{cite book}} to create the actual citation text.functionz.citation(frame)localpframe=frame:getParent()localargs={};localsuggestions={};localerror_text,error_state;localconfig={};fork,vinpairs(frame.args)doconfig[k]=v;args[k]=v;endfork,vinpairs(pframe.args)doifv~=''thenifnotvalidate(k)thenerror_text="";iftype(k)~='string'then-- Exclude empty numbered parametersifv:match("%S+")~=nilthenerror_text,error_state=seterror('text_ignored',{v},true);endelseifvalidate(k:lower())thenerror_text,error_state=seterror('parameter_ignored_suggest',{k,k:lower()},true);elseif#suggestions==0thensuggestions=mw.loadData('Module:Citation/CS1/Suggestions');endifsuggestions[k:lower()]~=nilthenerror_text,error_state=seterror('parameter_ignored_suggest',{k,suggestions[k:lower()]},true);elseerror_text,error_state=seterror('parameter_ignored',{k},true);endendiferror_text~=''thentable.insert(z.message_tail,{error_text,error_state});endendargs[k]=v;elseifargs[k]~=nilor(k=='postscript')thenargs[k]=v;endendreturncitation0(config,args)endreturnz