Module:Webarchive
- Ænglisc
- Аԥсшәа
- العربية
- Արեւմտահայերէն
- অসমীয়া
- Asturianu
- अवधी
- Авар
- Azərbaycanca
- تۆرکجه
- Basa Bali
- বাংলা
- 閩南語 / Bân-lâm-gí
- भोजपुरी
- Bikol Central
- Български
- Bosanski
- Català
- Cebuano
- ChiTumbuka
- Corsu
- Cymraeg
- Dagbanli
- Dansk
- الدارجة
- Deutsch
- डोटेली
- Eesti
- Ελληνικά
- Español
- Esperanto
- Euskara
- فارسی
- Føroyskt
- Gaeilge
- Gaelg
- Galego
- گیلکی
- ગુજરાતી
- 한국어
- Hausa
- Հայերեն
- हिन्दी
- Bahasa Hulontalo
- Ilokano
- Bahasa Indonesia
- Íslenska
- Italiano
- עברית
- Jawa
- ಕನ್ನಡ
- ქართული
- Kurdî
- Ladin
- ລາວ
- Latviešu
- Lietuvių
- Ligure
- Magyar
- मैथिली
- Македонски
- മലയാളം
- मराठी
- მარგალური
- مصرى
- ဘာသာမန်
- مازِرونی
- Bahasa Melayu
- Minangkabau
- 閩東語 / Mìng-dĕ̤ng-ngṳ̄
- Mirandés
- Монгол
- မြန်မာဘာသာ
- Na Vosa Vakaviti
- नेपाली
- 日本語
- Нохчийн
- Norsk bokmål
- Norsk nynorsk
- ଓଡ଼ିଆ
- Oʻzbekcha / ўзбекча
- ਪੰਜਾਬੀ
- پنجابی
- ပအိုဝ်ႏဘာႏသာႏ
- پښتو
- ភាសាខ្មែរ
- Português
- Qaraqalpaqsha
- Română
- ᱥᱟᱱᱛᱟᱲᱤ
- Sardu
- Scots
- Shqip
- සිංහල
- Simple English
- سنڌي
- Slovenčina
- Slovenščina
- کوردی
- Српски / srpski
- Srpskohrvatski / српскохрватски
- Sunda
- Suomi
- Tagalog
- தமிழ்
- Taclḥit
- Taqbaylit
- Tarandíne
- တႆး
- తెలుగు
- Tetun
- ไทย
- Türkçe
- Türkmençe
- Українська
- اردو
- Vèneto
- Tiếng Việt
- Volapük
- Winaray
- Xitsonga
- ייִדיש
- Yorùbá
- 粵語
- Zazaki
- 中文
- Kumoring
Appearance
From Wikipedia, the free encyclopedia
This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing.
Page template-protected This module is currently protected from editing.
See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected.
See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected.
This module is rated as ready for general use. It has reached a mature state, is considered relatively stable and bug-free, and may be used wherever appropriate. It can be mentioned on help pages and other Wikipedia resources as an option for new users. To minimise server load and avoid disruptive output, improvements should be developed through sandbox testing rather than repeated trial-and-error editing.
Page template-protected This module is currently protected from editing.
See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected.
See the protection policy and protection log for more details. Please discuss any changes on the talk page; you may submit an edit request to ask an administrator to make an edit if it is uncontroversial or supported by consensus. You may also request that this page be unprotected.
Warning This Lua module is used on approximately 649,000 pages, or roughly 1% of all pages .
To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them.
To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them.
This module depends on the following other modules:
This module implements Template:webarchive (talk · links · edit).
This module uses Module:Webarchive/data to support configuration control and internationalization.
Tracking categories
- tracking archive sites
- Category:Webarchive template wayback links (630,043) – links to Wayback Machine
- Category:Webarchive template archiveis links (25,334) – links to Archive.Today
- Category:Webarchive template webcite links (2,180) – links to WebCite
- Category:Webarchive template other archives (2,689) – all the other archive sites that don't have their own tracking category
- Category:Webarchive template unknown archives (379) – the template doesn't recognize the archive URL; this may indicate an error in the data; or the template itself needs updating to reflect a new archive site
- tracking warnings and errors
- Category:Webarchive template warnings (473) – soft errors that don't prevent the template from working but leave a red message
- Category:Webarchive template errors (61) – errors typically requiring human intervention
The above documentation is transcluded from Module:Webarchive/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Subpages of this module.
Editors can experiment in this module's sandbox (edit | diff) and testcases (edit | run) pages.
Subpages of this module.
--[[ ---------------------------------- Lua module implementing the {{webarchive}} template. A merger of the functionality of three templates: {{wayback}}, {{webcite}} and {{cite archives}} ]] --[[--------------------------< D E P E N D E N C I E S >------------------------------------------------------ ]] require('strict'); localgetArgs=require('Module:Arguments').getArgs; --[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- ]] localcategories={};-- category names localconfig={};-- global configuration settings localdigits={};-- for i18n; table that translates local-wiki digits to western digits localerr_warn_msgs={};-- error and warning messages localexcepted_pages={}; localmonth_num={};-- for i18n; table that translates local-wiki month names to western digits localprefixes={};-- service provider tail string prefixes localservices={};-- archive service provider data from locals_text={};-- table of static text strings used to build final rendering localuncategorized_namespaces={};-- list of namespaces that we should not categorize localuncategorized_subpages={};-- list of subpages that should not be categorized --[[--------------------------< P A G E S C O P E I D E N T I F I E R S >---------------------------------- ]] localnon_western_digits;-- boolean flag set true when data.digits.enable is true localthis_page=mw.title.getCurrentTitle(); localtrack={};-- Associative array to hold tracking categories localulx={};-- Associative array to hold template data --[[--------------------------< S U B S T I T U T E >---------------------------------------------------------- Populates numbered arguments in a message string using an argument table. ]] localfunctionsubstitute(msg,args) returnargsandmw.message.newRawMessage(msg,args):plain()ormsg; end --[[--------------------------< tableLength >----------------------- Given a 1-D table, return number of elements ]] localfunctiontableLength(T) localcount=0 for_inpairs(T)docount=count+1end returncount end --[=[-------------------------< M A K E _ W I K I L I N K >---------------------------------------------------- Makes a wikilink; when both link and display text is provided, returns a wikilink in the form [[L|D]]; if only link is provided, returns a wikilink in the form [[L]]; if neither are provided or link is omitted, returns an empty string. ]=] localfunctionmake_wikilink(link,display,no_link) ifnil==no_linkthen iflinkand(''~=link)then ifdisplayand(''~=display)then returntable.concat({'[[',link,'|',display,']]'}); else returntable.concat({'[[',link,']]'}); end end returndisplayor'';-- link not set so return the display text else-- no_link ifdisplayand(''~=display)then-- if there is display text returndisplay;-- return that else returnlinkor'';-- return the target article name or empty string end end end --[[--------------------------< createTracking >----------------------- Return data in track[] ie. tracking categories ]] localfunctioncreateTracking() ifnotexcepted_pages[this_page.fullText]then-- namespace:title/fragment is allowed to be categorized (typically this module's / template's testcases page(s)) ifuncategorized_namespaces[this_page.nsText]then return'';-- this page not to be categorized so return empty string end for_,vinipairs(uncategorized_subpages)do-- cycle through page name patterns ifthis_page.text:match(v)then-- test page name against each pattern return'';-- this subpage type not to be categorized so return empty string end end end localout={}; iftableLength(track)>0then forkey,_inpairs(track)do-- loop through table table.insert(out,make_wikilink(key));-- and convert category names to links end end returntable.concat(out);-- concat into one big string; empty string if table is empty end --[[--------------------------< inlineError >----------------------- Critical error. Render output completely in red. Add to tracking category. This function called as the last thing before abandoning this module ]] localfunctioninlineError(msg,args) track[categories.error]=1 returntable.concat({ '<span style="font-size:100%" class="error citation-comment">Error in ',-- open the error message span config.tname,-- insert the local language template name ' template: ', substitute(msg,args),-- insert the formatted error message '.</span>',-- close the span createTracking()-- add the category }) end --[[--------------------------< inlineRed >----------------------- Render a text fragment in red, such as a warning as part of the final output. Add tracking category. ]] localfunctioninlineRed(msg,trackmsg) iftrackmsg=="warning"then track[categories.warning]=1; elseiftrackmsg=="error"then track[categories.error]=1; end return'<span style="font-size:100%" class="error citation-comment">'..msg..'</span>' end --[[--------------------------< base62 >----------------------- Convert base-62 to base-10 Credit: https://de.wikipedia.org/wiki/Modul:Expr ]] localfunctionbase62(value) localr=1-- default return value is input value is malformed ifvalue:match('%W')then-- value must only be in the set [0-9a-zA-Z] return;-- nil return when value contains extraneous characters end localn=#value-- number of characters in value localk=1 localc r=0 fori=n,1,-1do-- loop through all characters in value from ls digit to ms digit c=value:byte(i,i) ifc>=48andc<=57then-- character is digit 0-9 c=c-48 elseifc>=65andc<=90then-- character is ascii a-z c=c-55 else-- must be ascii A-Z c=c-61 end r=r+c*k-- accumulate this base62 character's value k=k*62-- bump for next end-- for i returnr end --[[--------------------------< D E C O D E _ D A T E >-------------------------------------------------------- Given a date string, return it in iso format along with an indicator of the date's format. Except that month names must be recognizable as legitimate month names with proper capitalization, and that the date string must match one of the recognized date formats, no error checking is done here; return nil else ]] localfunctiondecode_date(date_str) localpatterns={ ['dmy']={'^(%d%d?) +([^%s%d]+) +(%d%d%d%d)$','d','m','y'},-- %a does not recognize unicode combining characters used by some languages ['mdy']={'^([^%s%d]+) (%d%d?), +(%d%d%d%d)$','m','d','y'}, ['ymd']={'^(%d%d%d%d) +([^%s%d]+) (%d%d?)$','y','m','d'},-- not mos compliant at en.wiki but may be acceptible at other wikis }; localt={}; ifnon_western_digitsthen-- this wiki uses non-western digits? date_str=mw.ustring.gsub(date_str,'%d',digits);-- convert this wiki's non-western digits to western digits end ifdate_str:match('^%d%d%d%d%-%d%d%-%d%d$')then-- already an iso format date, return western digits form returndate_str,'iso'; end fork,vinpairs(patterns)do localc1,c2,c3=mw.ustring.match(date_str,patterns[k][1]);-- c1 .. c3 are captured but we don't know what they hold ifc1then-- set on match t={-- translate unspecified captures to y, m, and d [patterns[k][2]]=c1,-- fill the table of captures with the captures [patterns[k][3]]=c2,-- take index names from src_pattern table and assign sequential captures [patterns[k][4]]=c3, }; ifmonth_num[t.m]then-- when month not already a number t.m=month_num[t.m];-- replace valid month name with a number else returnnil,'iso';-- not a valid date form because month not valid end returnmw.ustring.format('%.4d-%.2d-%.2d',t.y,t.m,t.d),k;-- return date in iso format end end returnnil,'iso';-- date could not be decoded; return nil and default iso date end --[[--------------------------< makeDate >----------------------- Given year, month, day numbers, (zero-padded or not) return a full date in df format where df may be one of: mdy, dmy, iso, ymd on entry, year, month, day are presumed to be correct for the date that they represent; all are required in this module, makeDate() is sometimes given an iso-format date in year: makeDate (2018年09月20日, nil, nil, df) this works because table.concat() sees only one table member ]] localfunctionmakeDate(year,month,day,df) localformat={ ['dmy']='j F Y', ['mdy']='F j, Y', ['ymd']='Y F j', ['iso']='Y-m-d', }; localdate=table.concat({year,month,day},'-');-- assemble year-initial numeric-format date (zero padding not required here) ifnon_western_digitsthen-- this wiki uses non-western digits? date=mw.ustring.gsub(date,'%d',digits);-- convert this wiki's non-western digits to western digits end returnmw.getContentLanguage():formatDate(format[df],date); end --[[--------------------------< I S _ V A L I D _ D A T E >---------------------------------------------------- Returns true if date is after 31 December 1899 (why is 1900 the min year? shouldn't the internet's date-of-birth be min year?), not after today's date, and represents a valid date (29 February 2017 is not a valid date). Applies Gregorian leapyear rules. all arguments are required ]] localfunctionis_valid_date(year,month,day) localdays_in_month={31,28,31,30,31,30,31,31,30,31,30,31}; localmonth_length; localy,m,d; localtoday=os.date('*t');-- fetch a table of current date parts ifnotyearor''==yearornotmonthor''==monthornotdayor''==daythen returnfalse;-- something missing end y=tonumber(year); m=tonumber(month); d=tonumber(day); if1900>yortoday.year<yor1>mor12<mthen-- year and month are within bounds TODO: 1900? returnfalse; end if(2==m)then-- if February month_length=28;-- then 28 days unless if(0==(y%4)and(0~=(y%100)or0==(y%400)))then-- is a leap year? month_length=29;-- if leap year then 29 days in February end else month_length=days_in_month[m]; end if1>dormonth_length<dthen-- day is within bounds returnfalse; end -- here when date parts represent a valid date returnos.time({['year']=y,['month']=m,['day']=d,['hour']=0})<=os.time();-- date at midnight must be less than or equal to current date/time end --[[--------------------------< decodeWebciteDate >----------------------- Given a URI-path to Webcite (eg. /67xHmVFWP) return the encoded date in df format returns date string in df format - webcite date is a unix timestamp encoded as bae62 or the string 'query' ]] localfunctiondecodeWebciteDate(path,df) localdt={}; localdecode; dt=mw.text.split(path,"/") -- valid URL formats that are not base62 -- http://www.webcitation.org/query?id=1138911916587475 -- http://www.webcitation.org/query?url=http..&date=2012年06月01日+21:40:03 -- http://www.webcitation.org/1138911916587475 -- http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e -- http://www.webcitation.org/getfile.php?fileid=1c46e791d68e89e12d0c2532cc3cf629b8bc8c8e ifdt[2]:find('query',1,true)or dt[2]:find('cache',1,true)or dt[2]:find('getfile',1,true)or tonumber(dt[2])then return'query'; end decode=base62(dt[2]);-- base62 string -> exponential number ifnotdecodethen returnnil;-- nil return when dt[2] contains characters not in %w end dt=os.date('*t',string.format("%d",decode):sub(1,10))-- exponential number -> text -> first 10 characters (a unix timestamp) -> a table of date parts decode=makeDate(dt.year,dt.month,dt.day,'iso');-- date comparisons are all done in iso format with western digits ifnon_western_digitsthen-- this wiki uses non-western digits? decode=mw.ustring.gsub(decode,'%d',digits);-- convert this wiki's non-western digits to western digits end returndecode; end --[[--------------------------< decodeWaybackDate >----------------------- Given a URI-path to Wayback (eg. /web/20160901010101/http://example.com ) or Library of Congress Web Archives (eg. /all/20160901010101/http://example.com) or UK Government Web Archive (eg. /ukgwa/20160901010101/http://example.com or /tna/20160901010101/http://example.com) return the formatted date eg. "September 1, 2016" in df format Handle non-digits in snapshot ID such as "re_" and "-" and "*" returns two values: first value is one of these: valid date string in df format - wayback date is valid (including the text string 'index' when date is '/*/') empty string - wayback date is malformed (less than 8 digits, not a valid date) nil - wayback date is '/save/' or otherwise not a number second return value is an appropriate 'message' may or may not be formatted ]] localfunctiondecodeWaybackDate(path,df) localmsg,snapdate; snapdate=path:gsub('^/web/',''):gsub('^/all/',''):gsub('^/ukgwa/',''):gsub('^/tna/',''):gsub('^/','');-- remove leading /web/, /all/, /ukgwa/, /tna/, or / snapdate=snapdate:match('^[^/]+');-- get timestamp ifsnapdate=="*"then-- eg. /web/*/http.., etc. return'index';-- return indicator that this url has an index date end snapdate=snapdate:gsub('%a%a_%d?$',''):gsub('%-','');-- from date, remove any trailing "re_", dashes msg=''; ifsnapdate:match('%*$')then-- a trailing '*' causes calendar display at archive .org snapdate=snapdate:gsub('%*$','');-- remove so not part of length calc later msg=inlineRed(err_warn_msgs.ts_cal,'warning');-- make a message end ifnottonumber(snapdate)then returnnil,'ts_nan';-- return nil (fatal error flag) and message selector end localdlen=snapdate:len(); ifdlen<8then-- we need 8 digits TODO: but shouldn't this be testing for 14 digits? return'',inlineRed(err_warn_msgs.ts_short,'error');-- return empty string and error message end localyear,month,day=snapdate:match('(%d%d%d%d)(%d%d)(%d%d)');-- no need for snapdatelong here ifnotis_valid_date(year,month,day)then return'',inlineRed(err_warn_msgs.ts_date,'error');-- return empty string and error message end snapdate=table.concat({year,month,day},'-');-- date comparisons are all done in iso format if14==dlenthen returnsnapdate,msg;-- return date with message if any else returnsnapdate,msg..inlineRed(err_warn_msgs.ts_len,'warning');-- return date with warning message(s) end end --[[--------------------------< decodeArchiveisDate >----------------------- Given an Archive.is "long link" URI-path (e.g. /2016.08.28-144552/http://example.com) return the date in df format (e.g. if df = dmy, return 28 August 2016) Handles "." and "-" in snapshot date, so 2016年08月28日-144552 is same as 20160828144552 returns two values: first value is one of these: valid date string in df format - archive.is date is valid (including the text string 'short link' when url is the short form) empty string - wayback date is malformed (not a number, less than 8 digits, not a valid date) nil - wayback date is '/save/' second return value is an appropriate 'message' may or may not be formatted ]] localfunctiondecodeArchiveisDate(path,df) localsnapdate ifpath:match('^/%w+$')then-- short form url path is '/' followed by some number of base 62 digits and nothing else return"short link"-- e.g. http://archive.is/hD1qz end snapdate=mw.text.split(path,'/')[2]:gsub('[%.%-]','');-- get snapshot date, e.g. 2016年08月28日-144552; remove periods and hyphens localdlen=string.len(snapdate) ifdlen<8then-- we need 8 digits TODO: but shouldn't this be testing for 14 digits? return'',inlineRed(err_warn_msgs.ts_short,'error');-- return empty string and error message end localyear,month,day=snapdate:match('(%d%d%d%d)(%d%d)(%d%d)');-- no need for snapdatelong here ifnotis_valid_date(year,month,day)then return'',inlineRed(err_warn_msgs.ts_date,'error');-- return empty string and error message end snapdate=table.concat({year,month,day},'-');-- date comparisons are all done in iso format if14==dlenthen returnsnapdate;-- return date else returnsnapdate,inlineRed(err_warn_msgs.ts_len,'warning');-- return date with warning message end end --[[--------------------------< serviceName >----------------------- Given a domain extracted by mw.uri.new() (eg. web.archive.org) set tail string and service ID ]] localfunctionserviceName(host,no_link) localtracking; localindex; host=host:lower():gsub('^web%.(.+)','%1'):gsub('^www%.(.+)','%1');-- lowercase, remove web. and www. subdomains ifservices[host]then index=host; else fork,_inpairs(services)do ifhost:find('%f[%a]'..k:gsub('([%.%-])','%%%1'))then index=k; break; end end end ifindexthen localout={''};-- empty string in [1] so that concatenated result has leading single space ulx.url1.service=services[index][4]or'other'; tracking=services[index][5]orcategories.other; -- build tail string iffalse==services[index][1]then-- select prefix table.insert(out,prefixes.at); elseiftrue==services[index][1]then table.insert(out,prefixes.atthe); else table.insert(out,services[index][1]); end table.insert(out,make_wikilink(services[index][2],services[index][3],no_link));-- add article wikilink ifservices[index][6]then-- add tail postfix if it exists table.insert(out,services[index][6]); end ulx.url1.tail=table.concat(out,' ');-- put it all together; result has leading space character else-- here when unknown archive ulx.url1.service='other'; tracking=categories.unknown; ulx.url1.tail=table.concat({'',prefixes.at,host,inlineRed(err_warn_msgs.unknown_url,error)},' '); end track[tracking]=1 end --[[--------------------------< parseExtraArgs >----------------------- Parse numbered arguments starting at 2, such as url2..url10, date2..date10, title2..title10 For example: {{webarchive |url=.. |url4=.. |url7=..}} Three url arguments not in numeric sequence (1..4..7). Function only processes arguments numbered 2 or greater (in this case 4 and 7) It creates numeric sequenced table entries like: urlx.url2.url = <argument value for url4> urlx.url3.url = <argument value for url7> Returns the number of URL arguments found numbered 2 or greater (in this case returns "2") ]] localfunctionparseExtraArgs(args) locali,j,argurl,argurl2,argdate,argtitle j=2 fori=2,config.maxurlsdo argurl="url"..i ifargs[argurl]then argurl2="url"..j ulx[argurl2]={} ulx[argurl2]["url"]=args[argurl] argdate="date"..i ifargs[argdate]then ulx[argurl2]["date"]=args[argdate] else ulx[argurl2]["date"]=inlineRed(err_warn_msgs.date_miss,'warning'); end argtitle="title"..i ifargs[argtitle]then ulx[argurl2]["title"]=args[argtitle] else ulx[argurl2]["title"]=nil end j=j+1 end end ifj==2then return0 else returnj-2 end end --[[--------------------------< comma >----------------------- Given a date string, return "," if it's MDY ]] localfunctioncomma(date) return(dateanddate:match('%a+ +%d%d?(,) +%d%d%d%d'))or''; end --[[--------------------------< createRendering >----------------------- Return a rendering of the data in ulx[][] ]] localfunctioncreateRendering() localdisplayfield localout={}; localindex_date,msg=ulx.url1.date:match('(index)(.*)');-- when ulx.url1.date extract 'index' text and message text (if there is a message) ulx.url1.date=ulx.url1.date:gsub('index.*','index');-- remove message if'none'==ulx.url1.formatthen-- For {{wayback}}, {{webcite}} table.insert(out,'[');-- open extlink markup table.insert(out,ulx.url1.url);-- add url ifulx.url1.titlethen table.insert(out,' ')-- the required space table.insert(out,ulx.url1.title)-- the title table.insert(out,']');-- close extlink markup table.insert(out,ulx.url1.tail);-- tail text ifulx.url1.datethen table.insert(out,' (');-- open date text; TODO: why the html entity? replace with regular space? table.insert(out,'index'==ulx.url1.dateands_text.archiveors_text.archived);-- add text table.insert(out,' ');-- insert a space table.insert(out,ulx.url1.date);-- add date table.insert(out,')');-- close date text end else-- no title ifindex_datethen-- when url date is 'index' table.insert(out,table.concat({' ',s_text.Archive_index,']'}));-- add the index link label table.insert(out,msgor'');-- add date mismatch message when url date is /*/ and |date= has valid date else table.insert(out,table.concat({' ',s_text.Archived,'] '}));-- add link label for url has timestamp date (will include mismatch message if there is one) end ifulx.url1.datethen if'index'~=ulx.url1.datethen table.insert(out,ulx.url1.date);-- add date when data is not 'index' end table.insert(out,comma(ulx.url1.date));-- add ',' if date format is mdy table.insert(out,ulx.url1.tail);-- add tail text else-- no date table.insert(out,ulx.url1.tail);-- add tail text end end if0<ulx.url1.extraurlsthen-- For multiple archive URLs localtot=ulx.url1.extraurls+1 table.insert(out,'.')-- terminate first url table.insert(out,table.concat({' ',s_text.addlarchives,': '}));-- add header text fori=2,totdo-- loop through the additionals localindex=table.concat({'url',i});-- make an index displayfield=ulx[index]['title']and'title'or'date';-- choose display text table.insert(out,'[');-- open extlink markup table.insert(out,ulx[index]['url']);-- add the url table.insert(out,' ');-- the required space table.insert(out,ulx[index][displayfield]);-- add the label table.insert(out,']');-- close extlink markup table.insert(out,i==totand'.'or', ');-- add terminator end end returntable.concat(out);-- make a big string and done else-- For {{cite archives}} if'addlarchives'==ulx.url1.formatthen-- Multiple archive services table.insert(out,table.concat({s_text.addlarchives,': '}));-- add header text else-- Multiple pages from the same archive table.insert(out,table.concat({s_text.addlpages,' '}));-- add header text table.insert(out,ulx.url1.date);-- add date to header text table.insert(out,': ');-- close header text end localtot=ulx.url1.extraurls+1; fori=1,totdo-- loop through the additionals localindex=table.concat({'url',i});-- make an index table.insert(out,'[');-- open extlink markup table.insert(out,ulx[index]['url']);-- add url table.insert(out,' ');-- add required space displayfield=ulx[index]['title']; if'addlarchives'==ulx.url1.formatthen ifnotdisplayfieldthen displayfield=ulx[index]['date'] end else-- must be addlpages ifnotdisplayfieldthen displayfield=table.concat({s_text.Page,' ',i}); end end table.insert(out,displayfield);-- add title, date, page label text table.insert(out,']');-- close extlink markup table.insert(out,(i==totand'.'or', '));-- add terminator end returntable.concat(out);-- make a big string and done end end --[[--------------------------< P A R A M E T E R _ N A M E _ X L A T E >-------------------------------------- for internaltionalization, translate local-language parameter names to their English equivalents TODO: return error message if multiple aliases of the same canonical parameter name are found? returns two tables: new_args - holds canonical form parameters and their values either from translation or because the parameter was already in canonical form origin - maps canonical-form parameter names to their untranslated (local language) form for error messaging in the local language unrecognized parameters are ignored ]] localfunctionparameter_name_xlate(args,params,enum_params) localname;-- holds modifiable name of the parameter name during evaluation localenum;-- for enumerated parameters, holds the enumerator during evaluation localfound=false;-- flag used to break out of nested for loops localnew_args={};-- a table that holds canonical and translated parameter k/v pairs localorigin={};-- a table that maps original (local language) parameter names to their canonical name for local language error messaging localunnamed_params;-- set true when unsupported positional parameters are detected fork,vinpairs(args)do-- loop through all of the arguments in the args table name=k;-- copy of original parameter name if'string'==type(k)then ifnon_western_digitsthen-- true when non-western digits supported at this wiki name=mw.ustring.gsub(name,'%d',digits);-- convert this wiki's non-western digits to western digits end enum=name:match('%d+$');-- get parameter enumerator if it exists; nil else ifnotenumthen-- no enumerator so looking for non-enumnerated parameters -- TODO: insert shortcut here? if params[name] then name holds the canonical parameter name; no need to search further forpname,aliasesinpairs(params)do-- loop through each parameter the params table for_,aliasinipairs(aliases)do-- loop through each alias in the parameter's aliases table ifname==aliasthen new_args[pname]=v;-- create a new entry in the new_args table origin[pname]=k;-- create an entry to make canonical parameter name to original local language parameter name found=true;-- flag so that we can break out of these nested for loops break;-- no need to search the rest of the aliases table for name so go on to the next k, v pair end end iffoundthen-- true when we found an alias that matched name found=false;-- reset the flag break;-- go do next args k/v pair end end else-- enumerated parameters name=name:gsub('%d$','#');-- replace enumeration digits with place holder for table search -- TODO: insert shortcut here? if num_params[name] then name holds the canonical parameter name; no need to search further forpname,aliasesinpairs(enum_params)do-- loop through each parameter the num_params table for_,aliasinipairs(aliases)do-- loop through each alias in the parameter's aliases table ifname==aliasthen pname=pname:gsub('#$',enum);-- replace the '#' place holder with the actual enumerator new_args[pname]=v;-- create a new entry in the new_args table origin[pname]=k;-- create an entry to make canonical parameter name to original local language parameter name found=true;-- flag so that we can break out of these nested for loops break;-- no need to search the rest of the aliases table for name so go on to the next k, v pair end end iffoundthen-- true when we found an alias that matched name found=false;-- reset the flag break;-- go do next args k/v pair end end end else unnamed_params=true;-- flag for unsupported positional parameters end end-- for k, v returnnew_args,origin,unnamed_params; end --[[--------------------------< W E B A R C H I V E >---------------------------------------------------------- template entry point ]] localfunctionwebarchive(frame) localargs=getArgs(frame); localdata=mw.loadData(table.concat({-- make a data module name; sandbox or live 'Module:Webarchive/data', frame:getTitle():find('sandbox',1,true)and'/sandbox'or''-- this instance is ./sandbox then append /sandbox })); categories=data.categories;-- fill in the forward declarations config=data.config; ifdata.digits.enablethen digits=data.digits;-- for i18n; table of digits in the local wiki's language non_western_digits=true;-- use_non_western_digits end err_warn_msgs=data.err_warn_msgs; excepted_pages=data.excepted_pages; month_num=data.month_num;-- for i18n; table of month names in the local wiki's language prefixes=data.prefixes; services=data.services; s_text=data.s_text; uncategorized_namespaces=data.uncategorized_namespaces; uncategorized_subpages=data.uncategorized_subpages; localorigin={};-- holds a map of English to local language parameter names used in the current template; not currently used localunnamed_params;-- boolean set to true when template call has unnamed parameters args,origin,unnamed_params=parameter_name_xlate(args,data.params,data.enum_params);-- translate parameter names in args to English localdate,format,msg,udate,uri,url; localldf='iso';-- when there is no |date= parameter, render url dates in iso format ifargs.urlandargs.url1then-- URL argument (first) returninlineError(data.crit_err_msgs.conflicting,{origin.url,origin.url1}); end url=args.urlorargs.url1; ifnoturlthen returninlineError(data.crit_err_msgs.empty); end -- these iabot bugs perportedly fixed; removing these causes lua script error --[[ -- at Template:Webarchive/testcases/Production; resolve that before deleting these tests if mw.ustring.find( url, "https://web.http", 1, true ) then -- track bug - TODO: IAbot bug; not known if the bug has been fixed; deferred track[categories.error] = 1; return inlineError (data.crit_err_msgs.iabot1); end if url == "https://web.archive.org/http:/" then -- track bug - TODO: IAbot bug; not known if the bug has been fixed; deferred track[categories.error] = 1; return inlineError (data.crit_err_msgs.iabot2); end ]] ifnot(url:lower():find('^http')orurl:find('^//'))then returninlineError(data.crit_err_msgs.invalid_url); end ulx.url1={} ulx.url1.url=url ulx.url1.extraurls=parseExtraArgs(args) localgood=false; good,uri=pcall(mw.uri.new,ulx.url1.url);-- get a table of uri parts from this url; protected mode to prevent lua error when ulx.url1.url is malformed ifnotgoodornil==uri.hostthen-- abandon when ulx.url1.url is malformed returninlineError(data.crit_err_msgs.invalid_url); end serviceName(uri.host,args.nolink) ifargs.dateandargs.date1then-- Date argument returninlineError(data.crit_err_msgs.conflicting,{origin.date,origin.date1}); end date=args.dateorargs.date1; date=dateanddate:gsub(' +',' ');-- replace multiple spaces with a single space ifdateandconfig.verifydatesthen if'*'==datethen date='index'; ldf='iso';-- set to default format elseif'mdy'==datethen date=nil;-- if date extracted from URL, ldf='mdy';-- then |date=mdy overrides iso elseif'dmy'==datethen date=nil;-- if date extracted from URL, ldf='dmy';-- then |date=dmy overrides iso elseif'ymd'==datethen date=nil;-- if date extracted from URL, ldf='ymd';-- then |date=ymd overrides iso else date,ldf=decode_date(date);-- get an iso format date from date and get date's original format end end if'wayback'==ulx.url1.serviceor'locwebarchives'==ulx.url1.serviceor'ukgwa'==ulx.url1.servicethen ifdatethen ifconfig.verifydatesthen ifldfthen udate,msg=decodeWaybackDate(uri.path);-- get the url date in iso format and format of date in |date=; 'index' when wayback url date is * ifnotudatethen-- this is the only 'fatal' error return returninlineError(data.crit_err_msgs[msg]); end ifudate~=datethen-- date comparison using iso format dates date=udate; msg=table.concat({ inlineRed(err_warn_msgs.mismatch,'warning'),-- add warning message msg,-- add message if there is one }); end end end else-- no |date= udate,msg=decodeWaybackDate(uri.path); ifnotudatethen-- this is the only 'fatal' error return returninlineError(data.crit_err_msgs[msg]); end if''==udatethen date=nil;-- unset else date=udate; end end elseif'webcite'==ulx.url1.servicethen ifdatethen ifconfig.verifydatesthen ifldfthen udate=decodeWebciteDate(uri.path);-- get the url date in iso format if'query'~=udatethen-- skip if query ifudate~=datethen-- date comparison using iso format dates date=udate; msg=table.concat({ inlineRed(err_warn_msgs.mismatch,'warning'), }); end end end end else date=decodeWebciteDate(uri.path,"iso") ifdate=="query"then date=nil;-- unset msg=inlineRed(err_warn_msgs.date_miss,'warning'); elseifnotdatethen-- invalid base62 string date=inlineRed(err_warn_msgs.date1,'error'); end end elseif'archiveis'==ulx.url1.servicethen ifdatethen ifconfig.verifydatesthen ifldfthen udate,msg=decodeArchiveisDate(uri.path)-- get the url date in iso format if'short link'~=udatethen-- skip if short link ifudate~=datethen-- date comparison using iso format dates date=udate; msg=table.concat({ inlineRed(err_warn_msgs.mismatch,'warning'),-- add warning message msg,-- add message if there is one }); end end end end else-- no |date= udate,msg=decodeArchiveisDate(uri.path,"iso") ifudate=="short link"then date=nil;-- unset msg=inlineRed(err_warn_msgs.date_miss,'warning'); elseif''==udatethen date=nil;-- unset else date=udate; end end else-- some other service ifnotdatethen msg=inlineRed(err_warn_msgs.date_miss,'warning'); end end if'index'==datethen ulx.url1.date=date..(msgor'');-- create index + message (if there is one) elseifdatethen ulx.url1.date=makeDate(date,nil,nil,ldf)..(msgor'');-- create a date in the wiki's local language + message (if there is one) else ulx.url1.date=msg; end format=args.format;-- Format argument ifnotformatthen format="none" else fork,vinpairs(data.format_vals)do-- |format= accepts two specific values loop through a table of those values localfound;-- declare a nil flag for_,pinipairs(v)do-- loop through local language variants ifformat==pthen-- when |format= value matches format=k;-- use name from table key found=true;-- declare found so that we can break out of outer for loop break;-- break out of inner for loop end end iffoundthen break; end end ifformat=="addlpages"then ifnotulx.url1.datethen format="none" end elseifformat=="addlarchives"then format="addlarchives" else format="none" end end ulx.url1.format=format ifargs.titleandargs.title1then-- Title argument returninlineError(data.crit_err_msgs.conflicting,{origin.title,origin.title1}); end ulx.url1.title=args.titleorargs.title1; localrend=createRendering() ifnotrendthen returninlineError(data.crit_err_msgs.unknown); end returnrend..((unnamed_paramsandinlineRed(err_warn_msgs.unnamed_params,'warning'))or'')..createTracking(); end --[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ ]] return{webarchive=webarchive};