Module:Citation/CS1/COinS

localcoins={};--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------]]localis_set,in_array,remove_wiki_link;-- functions in Module:Citation/CS1/Utilitieslocalcfg;-- table of configuration tables that are defined in Module:Citation/CS1/Configuration--[[--------------------------< S T R I P _ A P O S T R O P H E _ M A R K U P >--------------------------------Strip wiki italic and bold markup from argument so that it doesn't contaminate COinS metadata.This function strips common patterns of apostrophe markup. We presume that editors who have taken the time tomarkup a title have, as a result, provided valid markup. When they don't, some single apostrophes are left behind.]]localfunctionstrip_apostrophe_markup(argument)ifnotis_set(argument)thenreturnargument;endifargument:find("''",1,true)==nilthen-- Is there at least one double apostrophe? If not, exit.returnargument;endwhiletruedoifargument:find("'''''",1,true)then-- bold italic (5)argument=argument:gsub("%'%'%'%'%'","");-- remove all instances of itelseifargument:find("''''",1,true)then-- italic start and end without content (4)argument=argument:gsub("%'%'%'%'","");elseifargument:find("'''",1,true)then-- bold (3)argument=argument:gsub("%'%'%'","");elseifargument:find("''",1,true)then-- italic (2)argument=argument:gsub("%'%'","");elsebreak;endendreturnargument;-- doneend--[[--------------------------< M A K E _ C O I N S _ T I T L E >----------------------------------------------Makes a title for COinS from Title and / or ScriptTitle (or any other name-script pairs)Apostrophe markup (bold, italics) is stripped from each value so that the COinS metadata isn't corrupted with stringsof %27%27...]]localfunctionmake_coins_title(title,script)ifis_set(title)thentitle=strip_apostrophe_markup(title);-- strip any apostrophe markupelsetitle='';-- if not set, make sure title is an empty stringendifis_set(script)thenscript=script:gsub('^%l%l%s*:%s*','');-- remove language prefix if present (script value may now be empty string)script=strip_apostrophe_markup(script);-- strip any apostrophe markupelsescript='';-- if not set, make sure script is an empty stringendifis_set(title)andis_set(script)thenscript=' '..script;-- add a space before we concatenateendreturntitle..script;-- return the concatenationend--[[--------------------------< E S C A P E _ L U A _ M A G I C _ C H A R S >----------------------------------Returns a string where all of lua's magic characters have been escaped. This is important because functions likestring.gsub() treat their pattern and replace strings as patterns, not literal strings.]]localfunctionescape_lua_magic_chars(argument)argument=argument:gsub("%%","%%%%");-- replace % with %%argument=argument:gsub("([%^%$%(%)%.%[%]%*%+%-%?])","%%%1");-- replace all other lua magic pattern charactersreturnargument;end--[[--------------------------< G E T _ C O I N S _ P A G E S >------------------------------------------------Extract page numbers from external wikilinks in any of the |page=, |pages=, or |at= parameters for use in COinS.]]localfunctionget_coins_pages(pages)localpattern;ifnotis_set(pages)thenreturnpages;end-- if no page numbers then we're donewhiletruedopattern=pages:match("%[(%w*:?//[^ ]+%s+)[%w%d].*%]");-- pattern is the opening bracket, the url and following space(s): "[url "ifnil==patternthenbreak;end-- no more urlspattern=escape_lua_magic_chars(pattern);-- pattern is not a literal string; escape lua's magic pattern characterspages=pages:gsub(pattern,"");-- remove as many instances of pattern as possibleendpages=pages:gsub("[%[%]]","");-- remove the bracketspages=pages:gsub("–","-");-- replace endashes with hyphenspages=pages:gsub("&%w+;","-");-- and replace html entities (&ndash; etc.) with hyphens; do we need to replace numerical entities like &#32; and the like?returnpages;end--[=[-------------------------< C O I N S _ R E P L A C E _ M A T H _ S T R I P M A R K E R >------------------There are three options for math markup rendering that depend on the editor's math preference settings. Thesesettings are at [[Special:Preferences#mw-prefsection-rendering]] and are PNG images TeX source MathML with SVG or PNG fallbackAll three are heavy with html and css which doesn't belong in the metadata.Without this function, the metadata saved in the raw wikitext contained the rendering determined by the settingsof the last editor to save the page.This function gets the rendered form of an equation according to the editor's preference before the page is saved. Itthen searches the rendering for the text equivalent of the rendered equation and replaces the rendering with that sothat the page is saved without extraneous html/css markup and with a reasonably readable text form of the equation.When a replacement is made, this function returns true and the value with replacement; otherwise false and the intitalvalue. To replace multipe equations it is necesary to call this function from within a loop.]=]localfunctioncoins_replace_math_stripmarker(value)localstripmarker='\127UNIQ%-%-math%-[%a%d]+%-QINU\127';-- math stripmarker patternlocalrendering=value:match(stripmarker);-- is there a math stripmarkerifnotrenderingthen-- when value doesn't have a math stripmarker, abandon this testreturnfalse,value;endrendering=mw.text.unstripNoWiki(rendering);-- convert stripmarker into rendered value (or nil? ''? when math render error)ifrendering:match('alt="[^"]+"')then-- if PNG math optionrendering=rendering:match('alt="([^"]+)"');-- extract just the math textelseifrendering:match('$%s+.+%s+%$')then-- if TeX math option; $ is legit character that is escapes as \$rendering=rendering:match('$%s+(.+)%s+%$')-- extract just the math textelseifrendering:match('<annotation[^>]+>.+</annotation>')then-- if MathML math optionrendering=rendering:match('<annotation[^>]+>(.+)</annotation>')-- extract just the math textelsereturnfalse,value;-- had math stripmarker but not one of the three defined formsendreturntrue,value:gsub(stripmarker,rendering,1);end--[[--------------------------< C O I N S _ C L E A N U P >----------------------------------------------------Cleanup parameter values for the metadata by removing or replacing invisible characters and certain html entities.2015-12-10: there is a bug in mw.text.unstripNoWiki (). It replaced math stripmarkers with the appropriate contentwhen it shouldn't. See https://phabricator.wikimedia.org/T121085 and Wikipedia_talk:Lua#stripmarkers_and_mw.text.unstripNoWiki.28.29TODO: move the replacement patterns and replacement values into a table in /Configuration similar to the invisiblecharacters table?]]localfunctioncoins_cleanup(value)localreplaced=true;-- default state to get the do loop runningwhilereplaceddo-- loop until all math stripmarkers replacedreplaced,value=coins_replace_math_stripmarker(value);-- replace math stripmarker with text representation of the equationendvalue=value:gsub('\127UNIQ%-%-math%-[%a%d]+%-QINU\127',"MATH RENDER ERROR");-- one or more couldn't be replaced; insert vague error messagevalue=mw.text.unstripNoWiki(value);-- replace nowiki stripmarkers with their contentvalue=value:gsub('<span class="nowrap" style="padding%-left:0%.1em;">&#39;s</span>',"'s");-- replace {{'s}} template with simple apostrophe-svalue=value:gsub('&zwj;\226\128\138\039\226\128\139',"'");-- replace {{'}} with simple apostrophevalue=value:gsub('\226\128\138\039\226\128\139',"'");-- replace {{'}} with simple apostrophe (as of 2015-12-11)value=value:gsub('&nbsp;',' ');-- replace &nbsp; entity with plain spacevalue=value:gsub('\226\128\138',' ');-- replace hair space with plain spacevalue=value:gsub('&zwj;','');-- remove &zwj; entitiesvalue=value:gsub('[\226\128\141\226\128\139]','')-- remove zero-width joiner, zero-width spacevalue=value:gsub('[\194\173\009\010\013]',' ');-- replace soft hyphen, horizontal tab, line feed, carriage return with plain spacereturnvalue;end--[[--------------------------< C O I N S >--------------------------------------------------------------------COinS metadata (see <http://ocoins.info/>) allows automated tools to parse the citation information.]]localfunctionCOinS(data,class)if'table'~=type(data)ornil==next(data)thenreturn'';endfork,vinpairs(data)do-- spin through all of the metadata parameter valuesif'ID_list'~=kand'Authors'~=kthen-- except the ID_list and Author tables (author nowiki stripmarker done when Author table processed)data[k]=coins_cleanup(v);endendlocalctx_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(remove_wiki_link(value))});endend});ifin_array(class,{'arxiv','journal','news'})or(in_array(class,{'conference','interview','map','press release','web'})andis_set(data.Periodical))or('citation'==classandis_set(data.Periodical)andnotis_set(data.Encyclopedia))thenOCinSoutput.rft_val_fmt="info:ofi/fmt:kev:mtx:journal";-- journal metadata identifierif'arxiv'==classthen-- set genre according to the type of citation template we are renderingOCinSoutput["rft.genre"]="preprint";-- cite arxivelseif'conference'==classthenOCinSoutput["rft.genre"]="conference";-- cite conference (when Periodical set)elseif'web'==classthenOCinSoutput["rft.genre"]="unknown";-- cite web (when Periodical set)elseOCinSoutput["rft.genre"]="article";-- journal and other 'periodical' articlesendOCinSoutput["rft.jtitle"]=data.Periodical;-- journal onlyOCinSoutput["rft.atitle"]=data.Title;-- 'periodical' article titles-- these used only for periodicalsOCinSoutput["rft.ssn"]=data.Season;-- keywords: winter, spring, summer, fallOCinSoutput["rft.chron"]=data.Chron;-- free-form date componentsOCinSoutput["rft.volume"]=data.Volume;-- does not apply to booksOCinSoutput["rft.issue"]=data.Issue;OCinSoutput["rft.pages"]=data.Pages;-- also used in book metadataelseif'thesis'~=classthen-- all others except cite thesis are treated as 'book' metadata; genre distinguishesOCinSoutput.rft_val_fmt="info:ofi/fmt:kev:mtx:book";-- book metadata identifierif'report'==classor'techreport'==classthen-- cite report and cite techreportOCinSoutput["rft.genre"]="report";elseif'conference'==classthen-- cite conference when Periodical not setOCinSoutput["rft.genre"]="conference";OCinSoutput["rft.atitle"]=data.Chapter;-- conference paper as chapter in proceedings (book)elseifin_array(class,{'book','citation','encyclopaedia','interview','map'})thenifis_set(data.Chapter)thenOCinSoutput["rft.genre"]="bookitem";OCinSoutput["rft.atitle"]=data.Chapter;-- book chapter, encyclopedia article, interview in a book, or map titleelseif'map'==classor'interview'==classthenOCinSoutput["rft.genre"]='unknown';-- standalone map or interviewelseOCinSoutput["rft.genre"]='book';-- book and encyclopediaendendelse--{'audio-visual', 'AV-media-notes', 'DVD-notes', 'episode', 'interview', 'mailinglist', 'map', 'newsgroup', 'podcast', 'press release', 'serial', 'sign', 'speech', 'web'}OCinSoutput["rft.genre"]="unknown";endOCinSoutput["rft.btitle"]=data.Title;-- book onlyOCinSoutput["rft.place"]=data.PublicationPlace;-- book onlyOCinSoutput["rft.series"]=data.Series;-- book onlyOCinSoutput["rft.pages"]=data.Pages;-- book, journalOCinSoutput["rft.edition"]=data.Edition;-- book onlyOCinSoutput["rft.pub"]=data.PublisherName;-- book and dissertationelse-- cite thesisOCinSoutput.rft_val_fmt="info:ofi/fmt:kev:mtx:dissertation";-- dissertation metadata identifierOCinSoutput["rft.title"]=data.Title;-- dissertation (also patent but that is not yet supported)OCinSoutput["rft.degree"]=data.Degree;-- dissertation onlyOCinSoutput['rft.inst']=data.PublisherName;-- book and dissertationend-- and now common parameters (as much as possible)OCinSoutput["rft.date"]=data.Date;-- book, journal, dissertationfork,vinpairs(data.ID_list)do-- what to do about these? For now assume that they are common to all?-- if k == 'ISBN' then v = clean_isbn( v ) endifk=='ISBN'thenv=v:gsub("[^-0-9X]","");endlocalid=cfg.id_handlers[k].COinS;ifstring.sub(idor"",1,4)=='info'then-- for ids that are in the info:registryOCinSoutput["rft_id"]=table.concat{id,"/",v};elseifstring.sub(idor"",1,3)=='rft'then-- for isbn, issn, eissn, etc that have defined COinS keywordsOCinSoutput[id]=v;elseifidthen-- when cfg.id_handlers[k].COinS is not nilOCinSoutput["rft_id"]=table.concat{cfg.id_handlers[k].prefix,v};-- others; provide a urlendend--[[ for k, v in pairs( data.ID_list ) do -- what to do about these? For now assume that they are common to all? local id, value = cfg.id_handlers[k].COinS; if k == 'ISBN' then value = clean_isbn( v ); else value = v; end if string.sub( id or "", 1, 4 ) == 'info' then OCinSoutput["rft_id"] = table.concat{ id, "/", v }; else OCinSoutput[ id ] = value; end end]]locallast,first;fork,vinipairs(data.Authors)dolast,first=coins_cleanup(v.last),coins_cleanup(v.firstor'');-- replace any nowiki strip markers, non-printing or invisible characersifk==1then-- for the first author name onlyifis_set(last)andis_set(first)then-- set these COinS values if |first= and |last= specify the first author nameOCinSoutput["rft.aulast"]=last;-- book, journal, dissertationOCinSoutput["rft.aufirst"]=first;-- book, journal, dissertationelseifis_set(last)thenOCinSoutput["rft.au"]=last;-- book, journal, dissertation -- otherwise use this form for the first nameendelse-- for all other authorsifis_set(last)andis_set(first)thenOCinSoutput["rft.au"]=table.concat{last,", ",first};-- book, journal, dissertationelseifis_set(last)thenOCinSoutput["rft.au"]=last;-- book, journal, dissertationendendendOCinSoutput.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--[[--------------------------< S E T _ S E L E C T E D _ M O D U L E S >--------------------------------------Sets local cfg table and imported functions table to same (live or sandbox) as that used by the other modules.]]localfunctionset_selected_modules(cfg_table_ptr,utilities_page_ptr)cfg=cfg_table_ptr;is_set=utilities_page_ptr.is_set;-- import functions from select Module:Citation/CS1/Utilities modulein_array=utilities_page_ptr.in_array;remove_wiki_link=utilities_page_ptr.remove_wiki_link;endreturn{make_coins_title=make_coins_title,get_coins_pages=get_coins_pages,COinS=COinS,set_selected_modules=set_selected_modules,}