Module:Webarchive:संशोधन के बीच अंतर
'--[[ ---------------------------------- Lua module implementing the {{webarchive}} template. A merger of the functiona...' कय साथे नँवा पन्ना बनावा गय |
No edit summary |
||
पंक्ति १: | पंक्ति १: | ||
--[[ ---------------------------------- |
--[[ ---------------------------------- |
||
Lua module implementing the {{webarchive}} template. |
Lua module implementing the {{webarchive}} template. |
||
A merger of the functionality of three templates: {{wayback}}, {{webcite}} and {{cite archives}} |
A merger of the functionality of three templates: {{wayback}}, {{webcite}} and {{cite archives}} |
||
]] |
]] |
||
local p = {} |
|||
--[[--------------------------< |
--[[--------------------------< inlineError >----------------------- |
||
]] |
|||
Critical error. Render output completely in red. Add to tracking category. |
|||
require('Module:No globals'); |
|||
local getArgs = require ('Module:Arguments').getArgs; |
|||
]] |
|||
local function inlineError(arg, msg) |
|||
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- |
|||
]] |
|||
track["श्रेणी:वेबआर्काइव टेम्पलेट खराबी"] = 1 |
|||
local categories = {}; -- category names |
|||
return '<span style="font-size:100%" class="error citation-comment">Error in webarchive template: Check <code style="color:inherit; border:inherit; padding:inherit;">|' .. arg .. '=</code> value. ' .. msg .. '</span>' |
|||
local config = {}; -- global configuration settings |
|||
local digits = {}; -- for i18n; table that translates local-wiki digits to western digits |
|||
local err_warn_msgs = {}; -- error and warning messages |
|||
local excepted_pages = {}; |
|||
local month_num = {}; -- for i18n; table that translates local-wiki month names to western digits |
|||
local prefixes = {}; -- service provider tail string prefixes |
|||
local services = {}; -- archive service provider data from |
|||
local s_text = {}; -- table of static text strings used to build final rendering |
|||
local uncategorized_namespaces = {}; -- list of namespaces that we should not categorize |
|||
local uncategorized_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 >---------------------------------- |
|||
]] |
|||
local non_western_digits; -- boolean flag set true when data.digits.enable is true |
|||
local this_page = mw.title.getCurrentTitle(); |
|||
local track = {}; -- Associative array to hold tracking categories |
|||
local ulx = {}; -- 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. |
|||
]] |
|||
local function substitute (msg, args) |
|||
return args and mw.message.newRawMessage (msg, args):plain() or msg; |
|||
end |
end |
||
--[[--------------------------< inlineRed >----------------------- |
|||
Render a text fragment in red, such as a warning as part of the final output. |
|||
--[[--------------------------< tableLength >----------------------- |
|||
Add tracking category. |
|||
]] |
|||
Given a 1-D table, return number of elements |
|||
local function inlineRed(msg, trackmsg) |
|||
]] |
|||
local function tableLength(T) |
|||
local count = 0 |
|||
for _ in pairs(T) do count = count + 1 end |
|||
return count |
|||
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. |
|||
if trackmsg == "warning" then |
|||
]=] |
|||
track["श्रेणी:वेबआर्काइव टेम्पलेट चेतावनी"] = 1 |
|||
elseif trackmsg == "error" then |
|||
track["श्रेणी:वेबआर्काइव टेम्पलेटखराबी"] = 1 |
|||
end |
|||
return '<span style="font-size:100%" class="error citation-comment">' .. msg .. '</span>' |
|||
local function make_wikilink (link, display, no_link) |
|||
if nil == no_link then |
|||
if link and ('' ~= link) then |
|||
if display and ('' ~= display) then |
|||
return table.concat ({'[[', link, '|', display, ']]'}); |
|||
else |
|||
return table.concat ({'[[', link, ']]'}); |
|||
end |
|||
end |
|||
return display or ''; -- link not set so return the display text |
|||
else -- no_link |
|||
if display and ('' ~= display) then -- if there is display text |
|||
return display; -- return that |
|||
else |
|||
return link or ''; -- return the target article name or empty string |
|||
end |
|||
end |
|||
end |
end |
||
--[[--------------------------< trimArg >----------------------- |
|||
trimArg returns nil if arg is "" while trimArg2 returns 'true' if arg is "" |
|||
--[[--------------------------< createTracking >----------------------- |
|||
trimArg2 is for args that might accept an empty value, as an on/off switch like nolink= |
|||
]] |
|||
Return data in track[] ie. tracking categories |
|||
]] |
|||
local function createTracking() |
|||
if not excepted_pages[this_page.fullText] then -- namespace:title/fragment is allowed to be categorized (typically this module's / template's testcases page(s)) |
|||
if uncategorized_namespaces[this_page.nsText] then |
|||
return ''; -- this page not to be categorized so return empty string |
|||
end |
|||
for _,v in ipairs (uncategorized_subpages) do -- cycle through page name patterns |
|||
if this_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 |
|||
local out = {}; |
|||
if tableLength(track) > 0 then |
|||
for key, _ in pairs(track) do -- loop through table |
|||
table.insert (out, make_wikilink (key)); -- and convert category names to links |
|||
end |
|||
end |
|||
return table.concat (out); -- concat into one big string; empty string if table is empty |
|||
local function trimArg(arg) |
|||
if arg == "" or arg == nil then |
|||
return nil |
|||
else |
|||
return mw.text.trim(arg) |
|||
end |
|||
end |
end |
||
local function trimArg2(arg) |
|||
if arg == nil then |
|||
return nil |
|||
--[[--------------------------< inlineError >----------------------- |
|||
else |
|||
return mw.text.trim(arg) |
|||
Critical error. Render output completely in red. Add to tracking category. |
|||
end |
|||
This function called as the last thing before abandoning this module |
|||
]] |
|||
local function inlineError (msg, args) |
|||
track[categories.error] = 1 |
|||
return table.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 |
end |
||
--[[--------------------------< inlineRed >----------------------- |
|||
Render a text fragment in red, such as a warning as part of the final output. |
|||
Add tracking category. |
|||
]] |
|||
local function inlineRed(msg, trackmsg) |
|||
if trackmsg == "warning" then |
|||
track[categories.warning] = 1; |
|||
elseif trackmsg == "error" then |
|||
track[categories.error] = 1; |
|||
end |
|||
return '<span style="font-size:100%" class="error citation-comment">' .. msg .. '</span>' |
|||
end |
|||
--[[--------------------------< base62 >----------------------- |
--[[--------------------------< base62 >----------------------- |
||
Convert base-62 to base-10 |
Convert base-62 to base-10 |
||
Credit: https://de.wikipedia.org/wiki/Modul:Expr |
Credit: https://de.wikipedia.org/wiki/Modul:Expr |
||
]] |
]] |
||
local function base62( value ) |
local function base62( value ) |
||
local r = 1 -- default return value is input value is malformed |
|||
local r = 1 |
|||
if value:match ('%W') then -- value must only be in the set [0-9a-zA-Z] |
|||
return; -- nil return when value contains extraneous characters |
|||
end |
|||
if value:match( "^%w+$" ) then |
|||
local n = #value -- number of characters in value |
|||
local n = #value |
|||
local k = 1 |
|||
local c |
|||
r = 0 |
|||
r = 0 |
|||
for i = n, 1, -1 do -- loop through all characters in value from ls digit to ms digit |
|||
for i = n, 1, -1 do |
|||
c = value:byte( i, i ) |
|||
if c >= 48 and c <= 57 then -- character is digit 0-9 |
|||
if c >= 48 and c <= 57 then |
|||
c = c - 48 |
|||
c = c - 48 |
|||
elseif c >= 65 and c <= 90 then -- character is ascii a-z |
|||
elseif c >= 65 and c <= 90 then |
|||
c = c - 55 |
|||
c = c - 55 |
|||
else -- must be ascii A-Z |
|||
elseif c >= 97 and c <= 122 then |
|||
c = c - 61 |
|||
c = c - 61 |
|||
end |
|||
else -- How comes? |
|||
r = r + c * k -- accumulate this base62 character's value |
|||
r = 1 |
|||
k = k * 62 -- bump for next |
|||
break -- for i |
|||
end |
|||
r = r + c * k |
|||
return r |
|||
k = k * 62 |
|||
end -- for i |
|||
end |
|||
return r |
|||
end |
end |
||
--[[--------------------------< tableLength >----------------------- |
|||
Given a 1-D table, return number of elements |
|||
--[[--------------------------< 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 |
|||
local function tableLength(T) |
|||
]] |
|||
local count = 0 |
|||
for _ in pairs(T) do count = count + 1 end |
|||
local function decode_date (date_str) |
|||
return count |
|||
local patterns = { |
|||
['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 |
|||
}; |
|||
local t = {}; |
|||
if non_western_digits then -- 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 |
|||
if date_str:match ('^%d%d%d%d%-%d%d%-%d%d$') then -- already an iso format date, return western digits form |
|||
return date_str, 'iso'; |
|||
end |
|||
for k, v in pairs (patterns) do |
|||
local c1, c2, c3 = mw.ustring.match (date_str, patterns[k][1]); -- c1 .. c3 are captured but we don't know what they hold |
|||
if c1 then -- 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, |
|||
}; |
|||
if month_num[t.m] then -- when month not already a number |
|||
t.m = month_num[t.m]; -- replace valid month name with a number |
|||
else |
|||
return nil, 'iso'; -- not a valid date form because month not valid |
|||
end |
|||
return mw.ustring.format ('%.4d-%.2d-%.2d', t.y, t.m, t.d), k; -- return date in iso format |
|||
end |
|||
end |
|||
return nil, 'iso'; -- date could not be decoded; return nil and default iso date |
|||
end |
end |
||
--[[--------------------------< makeDate >----------------------- |
|||
--[[--------------------------< dateFormat >----------------------- |
|||
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 |
|||
Given a date string, return its format: dmy, mdy, iso, ymd |
|||
on entry, year, month, day are presumed to be correct for the date that they represent; all are required |
|||
If unable to determine return nil |
|||
]] |
|||
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 |
|||
local function dateFormat(date) |
|||
]] |
|||
local dt = {} |
|||
local function makeDate (year, month, day, df) |
|||
dt.split = {} |
|||
['dmy'] = 'j F Y', |
|||
['mdy'] = 'F j, Y', |
|||
['ymd'] = 'Y F j', |
|||
['iso'] = 'Y-m-d', |
|||
}; |
|||
dt.split = mw.text.split(date, "-") |
|||
local date = table.concat ({year, month, day}, '-'); -- assemble year-initial numeric-format date (zero padding not required here) |
|||
if tableLength(dt.split) == 3 then |
|||
if tonumber(dt.split[1]) > 1900 and tonumber(dt.split[1]) < 2200 and tonumber(dt.split[2]) and tonumber(dt.split[3]) then |
|||
return "iso" |
|||
else |
|||
return nil |
|||
end |
|||
end |
|||
dt.split = mw.text.split(date, " ") |
|||
if non_western_digits then --this wiki uses non-western digits? |
|||
if tableLength(dt.split) == 3 then |
|||
date = mw.ustring.gsub (date, '%d', digits); -- convert this wiki's non-western digits to western digits |
|||
if tonumber(dt.split[3]) then |
|||
end |
|||
if tonumber(dt.split[3]) > 1900 and tonumber(dt.split[3]) < 2200 then |
|||
if tonumber(dt.split[1]) then |
|||
return "dmy" |
|||
else |
|||
return "mdy" |
|||
end |
|||
else |
|||
if tonumber(dt.split[1]) then |
|||
if tonumber(dt.split[1]) > 1900 and tonumber(dt.split[1]) < 2200 then |
|||
return "ymd" |
|||
end |
|||
end |
|||
end |
|||
end |
|||
end |
|||
return nil |
|||
return mw.getContentLanguage():formatDate (format[df], date); |
|||
end |
end |
||
--[[--------------------------< makeDate >----------------------- |
|||
Given a zero-padded 4-digit year, 2-digit month and 2-digit day, return a full date in df format |
|||
--[[--------------------------< I S _ V A L I D _ D A T E >---------------------------------------------------- |
|||
df = mdy, dmy, iso, ymd |
|||
]] |
|||
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. |
|||
local function makeDate(year, month, day, df) |
|||
all arguments are required |
|||
if not year or year == "" or not month or month == "" or not day or day == "" then |
|||
]] |
|||
return nil |
|||
end |
|||
local zmonth = month -- month with leading 0 |
|||
local function is_valid_date (year, month, day) |
|||
month = month:match("0*(%d+)") -- month without leading 0 |
|||
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
|||
if tonumber(month) < 1 or tonumber(month) > 12 then |
|||
local month_length; |
|||
return year |
|||
local y, m, d; |
|||
end |
|||
local today = os.date ('*t'); -- fetch a table of current date parts |
|||
local nmonth = os.date("%B", os.time{year=2000, month=month, day=1} ) -- month in name form |
|||
if not nmonth then |
|||
return year |
|||
end |
|||
local zday = day |
|||
if not year or '' == year or not month or '' == month or not day or '' == day then |
|||
day = zday:match("0*(%d+)") |
|||
return false; -- something missing |
|||
if tonumber(day) < 1 or tonumber(day) > 31 then |
|||
end |
|||
if df == "mdy" or df == "dmy" then |
|||
return nmonth .. " " .. year |
|||
y = tonumber (year); |
|||
elseif df == "iso" then |
|||
m = tonumber (month); |
|||
return year .. "-" .. zmonth |
|||
d = tonumber (day); |
|||
elseif df == "ymd" then |
|||
return year .. " " .. nmonth |
|||
else |
|||
return nmonth .. " " .. year |
|||
end |
|||
end |
|||
if df == "mdy" then |
|||
if 1900 > y or today.year < y or 1 > m or 12 < m then -- year and month are within bounds TODO: 1900? |
|||
return nmonth .. " " .. day .. ", " .. year -- September 1, 2016 |
|||
return false; |
|||
elseif df == "dmy" then |
|||
end |
|||
return day .. " " .. nmonth .. " " .. year -- 1 September 2016 |
|||
elseif df == "iso" then |
|||
return year .. "-" .. zmonth .. "-" .. zday -- 2016-09-01 |
|||
elseif df == "ymd" then |
|||
return year .. " " .. nmonth .. " " .. cday -- 2016 September 1 |
|||
else |
|||
return nmonth .. " " .. day .. ", " .. year -- September 1, 2016 |
|||
end |
|||
if (2==m) then -- if February |
|||
month_length = 28; -- then 28 days unless |
|||
if (0==(y%4) and (0~=(y%100) or 0==(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 |
|||
if 1 > d or month_length < d then -- day is within bounds |
|||
return false; |
|||
end |
|||
-- here when date parts represent a valid date |
|||
return os.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 |
end |
||
पंक्ति ३२३: | पंक्ति २०८: | ||
--[[--------------------------< decodeWebciteDate >----------------------- |
--[[--------------------------< decodeWebciteDate >----------------------- |
||
Given a URI-path to Webcite (eg. /67xHmVFWP) return the encoded date in df format |
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' |
|||
]] |
|||
]] |
|||
local function decodeWebciteDate(path, df) |
local function decodeWebciteDate(path, df) |
||
local dt = {} |
|||
dt.split = {} |
|||
local decode; |
|||
dt.split = mw.text.split(path, "/") |
|||
-- valid URL formats that are not base62 |
|||
-- http://www.webcitation.org/query?id=1138911916587475 |
|||
-- http://www.webcitation.org/1138911916587475 |
|||
-- http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e |
|||
if dt.split[2] == "query" or dt.split[2] == "cache" or tonumber(dt.split[2]) then |
|||
return "query" |
|||
end |
|||
dt.full = os.date("%Y %m %d", string.sub(string.format("%d", base62(dt.split[2])),1,10) ) |
|||
-- http://www.webcitation.org/query?id=1138911916587475 |
|||
dt.split = mw.text.split(dt.full, " ") |
|||
-- http://www.webcitation.org/query?url=http..&date=2012-06-01+21:40:03 |
|||
dt.year = dt.split[1] |
|||
-- http://www.webcitation.org/1138911916587475 |
|||
dt.month = dt.split[2] |
|||
-- http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e |
|||
dt.day = dt.split[3] |
|||
-- http://www.webcitation.org/getfile.php?fileid=1c46e791d68e89e12d0c2532cc3cf629b8bc8c8e |
|||
if not tonumber(dt.year) or not tonumber(dt.month) or not tonumber(dt.day) then |
|||
if dt[2]:find ('query', 1, true) or |
|||
return inlineRed("[Date error] (1)", "error") |
|||
dt[2]:find ('cache', 1, true) or |
|||
end |
|||
dt[2]:find ('getfile', 1, true) or |
|||
tonumber(dt[2]) then |
|||
return 'query'; |
|||
end |
|||
if tonumber(dt.month) > 12 or tonumber(dt.day) > 31 or tonumber(dt.month) < 1 then |
|||
decode = base62(dt[2]); -- base62 string -> exponential number |
|||
return inlineRed("[Date error] (2)", "error") |
|||
if not decode then |
|||
end |
|||
return nil; -- nil return when dt[2] contains characters not in %w |
|||
if tonumber(dt.year) > tonumber(os.date("%Y")) or tonumber(dt.year) < 1900 then |
|||
end |
|||
return inlineRed("[Date error] (3)", "error") |
|||
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 |
|||
end |
|||
fulldate = makeDate(dt.year, dt.month, dt.day, df) |
|||
if not fulldate then |
|||
if non_western_digits then --this wiki uses non-western digits? |
|||
return inlineRed("[Date error] (4)", "error") |
|||
decode = mw.ustring.gsub (decode, '%d', digits); -- convert this wiki's non-western digits to western digits |
|||
else |
|||
end |
|||
return fulldate |
|||
end |
|||
return decode; |
|||
end |
end |
||
--[[--------------------------< snapDateToString >----------------------- |
|||
--[[--------------------------< decodeWaybackDate >----------------------- |
|||
Given a URI-path to Wayback (eg. /web/20160901010101/http://example.com ) |
Given a URI-path to Wayback (eg. /web/20160901010101/http://example.com ) |
||
return the formatted date eg. "September 1, 2016" in df format |
|||
or Library of Congress Web Archives (/all/20160901010101/http://example.com) |
|||
Handle non-digits in snapshot ID such as "re_" and "-" and "*" |
|||
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 |
|||
]] |
|||
local function decodeWaybackDate(path, df) |
local function decodeWaybackDate(path, df) |
||
local snapdate, snapdatelong, currdate, fulldate |
|||
local msg, snapdate; |
|||
local safe = path |
|||
snapdate = path:gsub ('^/all/', ''):gsub ('^/web/', ''):gsub ('^/', ''); -- remove leading '/all/', leading '/web/' or leading '/' |
|||
snapdate = string.gsub(safe, "^/w?e?b?/?", "") -- Remove leading "/web/" or "/" |
|||
snapdate = snapdate:match ('^[^/]+'); -- get timestamp |
|||
safe = snapdate |
|||
if snapdate == "*" then -- eg. /web/*/http.. or /all/*/http.. |
|||
local N = mw.text.split(safe, "/") |
|||
return 'index'; -- return indicator that this url has an index date |
|||
snapdate = N[1] |
|||
end |
|||
if snapdate == "*" then -- eg. /web/*/http.. |
|||
return "index" |
|||
end |
|||
safe = snapdate |
|||
snapdate = string.gsub(safe, "[a-z][a-z]_[0-9]?$", "") -- Remove any trailing "re_" from date |
|||
safe = snapdate |
|||
snapdate = string.gsub(safe, "[-]", "") -- Remove dashes from date eg. 2015-01-01 |
|||
safe = snapdate |
|||
snapdate = string.gsub(safe, "[*]$", "") -- Remove trailing "*" |
|||
if not tonumber(snapdate) then |
|||
snapdate = snapdate:gsub ('%a%a_%d?$', ''):gsub ('%-', ''); -- from date, remove any trailing "re_", dashes |
|||
return inlineRed("[Date error] (2)", "error") |
|||
end |
|||
local dlen = string.len(snapdate) |
|||
if dlen < 4 then |
|||
return inlineRed("[Date error] (3)", "error") |
|||
end |
|||
if dlen < 14 then |
|||
snapdatelong = snapdate .. string.rep("0", 14 - dlen) |
|||
else |
|||
snapdatelong = snapdate |
|||
end |
|||
local year = string.sub(snapdatelong, 1, 4) |
|||
local month = string.sub(snapdatelong, 5, 6) |
|||
local day = string.sub(snapdatelong, 7, 8) |
|||
if not tonumber(year) or not tonumber(month) or not tonumber(day) then |
|||
return inlineRed("[Date error] (4)", "error") |
|||
end |
|||
if tonumber(month) > 12 or tonumber(day) > 31 or tonumber(month) < 1 then |
|||
return inlineRed("[Date error] (5)", "error") |
|||
end |
|||
currdate = os.date("%Y") |
|||
if tonumber(year) > tonumber(currdate) or tonumber(year) < 1900 then |
|||
return inlineRed("[Date error] (6)", "error") |
|||
end |
|||
fulldate = makeDate(year, month, day, df) |
|||
msg = ''; |
|||
if not fulldate then |
|||
if snapdate:match ('%*$') then -- a trailing '*' causes calendar display at archive .org |
|||
return inlineRed("[Date error] (7)", "error") |
|||
snapdate = snapdate:gsub ('%*$', ''); -- remove so not part of length calc later |
|||
else |
|||
msg = inlineRed (err_warn_msgs.ts_cal, 'warning'); -- make a message |
|||
return fulldate |
|||
end |
|||
end |
|||
if not tonumber(snapdate) then |
|||
return nil, 'ts_nan'; -- return nil (fatal error flag) and message selector |
|||
end |
|||
local dlen = snapdate:len(); |
|||
if dlen < 8 then -- 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 |
|||
local year, month, day = snapdate:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- no need for snapdatelong here |
|||
if not is_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 |
|||
if 14 == dlen then |
|||
return snapdate, msg; -- return date with message if any |
|||
else |
|||
return snapdate, msg .. inlineRed (err_warn_msgs.ts_len, 'warning'); -- return date with warning message(s) |
|||
end |
|||
end |
end |
||
--[[--------------------------< |
--[[--------------------------< serviceName >----------------------- |
||
Given a domain extracted by mw.uri.new() (eg. web.archive.org) set tail string and service ID |
|||
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 |
|||
local function serviceName(host, nolink) |
|||
]] |
|||
local tracking = "श्रेणी:वेबआर्काइव टेम्पलेट अन्य आर्काइव" |
|||
local function decodeArchiveisDate(path, df) |
|||
local snapdate |
|||
local bracketopen = "[[" |
|||
if path:match ('^/%w+$') then -- short form url path is '/' followed by some number of base 62 digits and nothing else |
|||
local bracketclose = "]]" |
|||
return "short link" -- e.g. http://archive.is/hD1qz |
|||
if nolink then |
|||
end |
|||
bracketopen = "" |
|||
bracketclose = "" |
|||
end |
|||
ulx.url1.service = "other" |
|||
snapdate = mw.text.split (path, '/')[2]:gsub('[%.%-]', ''); -- get snapshot date, e.g. 2016.08.28-144552; remove periods and hyphens |
|||
ulx.url1.tail = " at " .. ulx.url1.host .. " " .. inlineRed("Error: unknown archive URL") |
|||
if mw.ustring.find( host, "archive.org", 1, plain ) then |
|||
local dlen = string.len(snapdate) |
|||
ulx.url1.service = "wayback" |
|||
if dlen < 8 then -- we need 8 digits TODO: but shouldn't this be testing for 14 digits? |
|||
ulx.url1.tail = bracketopen .. " वेबैक मशीन" .. bracketclose .." पर " |
|||
return '', inlineRed (err_warn_msgs.ts_short, 'error'); -- return empty string and error message |
|||
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट वेबैक कड़ी" |
|||
end |
|||
elseif mw.ustring.find( host, "webcitation.org", 1, plain ) then |
|||
ulx.url1.service = "webcite" |
|||
ulx.url1.tail = bracketopen .. "WebCite" .. bracketclose .." पर " |
|||
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट वेबसाइट कड़ी" |
|||
elseif mw.ustring.find( host, "archive.is", 1, plain ) then |
|||
ulx.url1.service = "archiveis" |
|||
ulx.url1.tail = bracketopen .. " आर्काइव.इज" .. bracketclose .. " पर " |
|||
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट आर्काइवइज कड़ी" |
|||
elseif mw.ustring.find( host, "archive.fo", 1, plain ) then |
|||
ulx.url1.service = "archiveis" |
|||
ulx.url1.tail = " at " .. bracketopen .. "Archive.is" .. bracketclose |
|||
tracking = "श्रेणी:Webarchive template archiveis links" |
|||
elseif mw.ustring.find( host, "archive.today", 1, plain ) then |
|||
ulx.url1.service = "archiveis" |
|||
ulx.url1.tail = " at " .. bracketopen .. "Archive.is" .. bracketclose |
|||
tracking = "श्रेणी:Webarchive template archiveis links" |
|||
elseif mw.ustring.find( host, "archive[-]it.org", 1, plain ) then |
|||
ulx.url1.service = "archiveit" |
|||
ulx.url1.tail = " at " .. bracketopen .. "Archive-It" .. bracketclose |
|||
elseif mw.ustring.find( host, "arquivo.pt", 1, plain) then |
|||
ulx.url1.tail = " at the " .. "Portuguese Web Archive" |
|||
elseif mw.ustring.find( host, "loc.gov", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. bracketopen .. "Library of Congress" .. bracketclose |
|||
elseif mw.ustring.find( host, "webharvest.gov", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. bracketopen .. "National Archives and Records Administration" .. bracketclose |
|||
elseif mw.ustring.find( host, "bibalex.org", 1, plain ) then |
|||
ulx.url1.tail = " at " .. "[[Bibliotheca_Alexandrina#Internet_Archive_partnership|Bibliotheca Alexandrina]]" |
|||
elseif mw.ustring.find( host, "collectionscanada", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. "Canadian Government Web Archive" |
|||
elseif mw.ustring.find( host, "haw.nsk", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. "Croatian Web Archive (HAW)" |
|||
elseif mw.ustring.find( host, "veebiarhiiv.digar.ee", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. "Estonian Web Archive" |
|||
elseif mw.ustring.find( host, "vefsafn.is", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. "[[National and University Library of Iceland]]" |
|||
elseif mw.ustring.find( host, "proni.gov", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. bracketopen .. "Public Record Office of Northern Ireland" .. bracketclose |
|||
elseif mw.ustring.find( host, "uni[-]lj.si", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. "Slovenian Web Archive" |
|||
elseif mw.ustring.find( host, "stanford.edu", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. "[[Stanford University Libraries|Stanford Web Archive]]" |
|||
elseif mw.ustring.find( host, "nationalarchives.gov.uk", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. bracketopen .. "UK Government Web Archive" .. bracketclose |
|||
elseif mw.ustring.find( host, "parliament.uk", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. bracketopen .. "UK Parliament's Web Archive" .. bracketclose |
|||
elseif mw.ustring.find( host, "webarchive.org.uk", 1, plain ) then |
|||
ulx.url1.tail = " at the " .. bracketopen .. "UK Web Archive" .. bracketclose |
|||
elseif mw.ustring.find( host, "nlb.gov.sg", 1, plain ) then |
|||
ulx.url1.tail = " at " .. "Web Archive Singapore" |
|||
elseif mw.ustring.find( host, "pandora.nla.gov.au", 1, plain ) then |
|||
ulx.url1.tail = " at " .. bracketopen .. "Pandora Archive" .. bracketclose |
|||
elseif mw.ustring.find( host, "screenshots.com", 1, plain ) then |
|||
ulx.url1.tail = " at " .. "Screenshots" |
|||
elseif mw.ustring.find( host, "wikiwix.com", 1, plain ) then |
|||
ulx.url1.tail = " विकिविक्स" .. " पर " |
|||
elseif mw.ustring.find( host, "perma.cc", 1, plain ) then |
|||
ulx.url1.tail = " at " .. bracketopen .. "Perma.cc" .. bracketclose |
|||
else |
|||
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट नामालूम आर्काइव" |
|||
end |
|||
track[tracking] = 1 |
|||
local year, month, day = snapdate:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- no need for snapdatelong here |
|||
if not is_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 |
|||
if 14 == dlen then |
|||
return snapdate; -- return date |
|||
else |
|||
return snapdate, 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 |
|||
]] |
|||
local function serviceName(host, no_link) |
|||
local tracking; |
|||
local index; |
|||
host = host:lower():gsub ('^web%.(.+)', '%1'):gsub ('^www%.(.+)', '%1'); -- lowercase, remove web. and www. subdomains |
|||
if services[host] then |
|||
index = host; |
|||
else |
|||
for k, _ in pairs (services) do |
|||
if host:find ('%f[%a]'..k:gsub ('([%.%-])', '%%%1')) then |
|||
index = k; |
|||
break; |
|||
end |
|||
end |
|||
end |
|||
if index then |
|||
local out = {''}; -- empty string in [1] so that concatenated result has leading single space |
|||
ulx.url1.service = services[index][4] or 'other'; |
|||
tracking = services[index][5] or categories.other; |
|||
-- build tail string |
|||
if false == services[index][1] then -- select prefix |
|||
table.insert (out, prefixes.at); |
|||
elseif true == 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 |
|||
if services[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 |
end |
||
--[[--------------------------< parseExtraArgs >----------------------- |
--[[--------------------------< parseExtraArgs >----------------------- |
||
Parse numbered arguments starting at 2, such as url2..url10, date2..date10, title2..title10 |
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") |
|||
]] |
]] |
||
local function parseExtraArgs( |
local function parseExtraArgs() |
||
local i, j, argurl, argurl2, argdate, argtitle |
|||
j = 2 |
|||
for i = 2, maxurls do |
|||
argurl = "url" .. i |
|||
if trimArg(args[argurl]) then |
|||
argurl2 = "url" .. j |
|||
ulx[argurl2] = {} |
|||
ulx[argurl2]["url"] = args[argurl] |
|||
argdate = "date" .. j |
|||
if trimArg(args[argdate]) then |
|||
ulx[argurl2]["date"] = args[argdate] |
|||
else |
|||
ulx[argurl2]["date"] = inlineRed("[Date missing]", "warning") |
|||
end |
|||
argtitle = "title" .. j |
|||
if trimArg(args[argtitle]) then |
|||
argtitle = "title" .. j |
|||
ulx[argurl2]["title"] = args[argtitle] |
|||
else |
|||
ulx[argurl2]["title"] = args[argtitle] |
|||
ulx[argurl2]["title"] = nil |
|||
else |
|||
end |
|||
ulx[argurl2]["title"] = nil |
|||
j = j + 1 |
|||
end |
|||
end |
|||
end |
|||
end |
|||
if j == 2 then |
|||
return 0 |
|||
else |
|||
return j - 2 |
|||
end |
|||
if j == 2 then |
|||
return 0 |
|||
else |
|||
return j - 2 |
|||
end |
|||
end |
end |
||
--[[--------------------------< comma >----------------------- |
--[[--------------------------< comma >----------------------- |
||
Given a date string, return "," if it's MDY |
Given a date string, return "," if it's MDY |
||
]] |
]] |
||
local function comma(date) |
local function comma(date) |
||
local N = mw.text.split(date, " ") |
|||
return (date and date:match ('%a+ +%d%d?(,) +%d%d%d%d')) or ''; |
|||
local O = mw.text.split(N[1], "-") -- for ISO |
|||
if O[1] == "index" then return "" end |
|||
if not tonumber(O[1]) then |
|||
return "," |
|||
else |
|||
return "" |
|||
end |
|||
end |
end |
||
--[[--------------------------< createTracking >----------------------- |
|||
Return data in track[] ie. tracking categories |
|||
--[[--------------------------< createRendering >----------------------- |
|||
]] |
|||
Return a rendering of the data in ulx[][] |
|||
local function createTracking() |
|||
]] |
|||
local |
local sand = "" |
||
if tableLength(track) > 0 then |
|||
for key,_ in pairs(track) do |
|||
sand = sand .. "[[" .. key .. "]]" |
|||
end |
|||
end |
|||
return sand |
|||
local displayfield |
|||
local out = {}; |
|||
local period1 = ''; -- For backwards compat with {{wayback}} |
|||
local period2 = '.'; |
|||
local index_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.format then -- For {{wayback}}, {{webcite}} |
|||
table.insert (out, '['); -- open extlink markup |
|||
table.insert (out, ulx.url1.url); -- add url |
|||
if ulx.url1.title then |
|||
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 |
|||
if ulx.url1.date then |
|||
table.insert (out, ' ('); -- open date text; TODO: why the html entity? replace with regular space? |
|||
table.insert (out, 'index' == ulx.url1.date and s_text.archive or s_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 |
|||
if index_date then -- when url date is 'index' |
|||
table.insert (out, table.concat ({' ', s_text.Archive_index, ']'})); -- add the index link label |
|||
table.insert (out, msg or ''); -- 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 |
|||
if ulx.url1.date then |
|||
if 'wayback' == ulx.url1.service then |
|||
period1 = '.'; |
|||
period2 = ''; |
|||
end |
|||
if 'index' ~= ulx.url1.date then |
|||
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 |
|||
table.insert (out, period1); -- terminate |
|||
else -- no date |
|||
table.insert (out, ulx.url1.tail); -- add tail text |
|||
end |
|||
end |
|||
if 0 < ulx.url1.extraurls then -- For multiple archive URLs |
|||
local tot = ulx.url1.extraurls + 1 |
|||
table.insert (out, period2); -- terminate first url |
|||
table.insert (out, table.concat ({' ', s_text.addlarchives, ': '})); -- add header text |
|||
for i=2, tot do -- loop through the additionals |
|||
local index = 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==tot and '.' or ', '); -- add terminator |
|||
end |
|||
end |
|||
return table.concat (out); -- make a big string and done |
|||
else -- For {{cite archives}} |
|||
if 'addlarchives' == ulx.url1.format then -- 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 |
|||
local tot = ulx.url1.extraurls + 1; |
|||
for i=1, tot do -- loop through the additionals |
|||
local index = 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.format then |
|||
if not displayfield then |
|||
displayfield = ulx[index]['date'] |
|||
end |
|||
else -- must be addlpages |
|||
if not displayfield then |
|||
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==tot and '.' or ', ')); -- add terminator |
|||
end |
|||
return table.concat (out); -- make a big string and done |
|||
end |
|||
end |
end |
||
--[[--------------------------< createRendering >----------------------- |
|||
Return a rendering of the data in ulx[][] |
|||
--[[--------------------------< 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 |
|||
local function createRendering() |
|||
TODO: return error message if multiple aliases of the same canonical parameter name are found? |
|||
local sand, displayheader, displayfield |
|||
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 |
|||
local period1 = "" -- For backwards compat with {{wayback}} |
|||
unrecognized parameters are ignored |
|||
local period2 = "." |
|||
local indexstr = "archived" |
|||
if ulx.url1.date == "index" then |
|||
indexstr = "archive" |
|||
end |
|||
-- For {{wayback}}, {{webcite}} |
|||
if ulx.url1.format == "none" then |
|||
]] |
|||
if not ulx.url1.title and not ulx.url1.date then -- No title. No date |
|||
sand = "[" .. ulx.url1.url .. " Archived]" .. ulx.url1.tail |
|||
elseif not ulx.url1.title and ulx.url1.date then -- No title. Date. |
|||
if ulx.url1.service == "wayback" then |
|||
period1 = "." |
|||
period2 = "" |
|||
end |
|||
sand = "[" .. ulx.url1.url .. " Archived] " .. ulx.url1.date .. comma(ulx.url1.date) .. ulx.url1.tail .. period1 |
|||
elseif ulx.url1.title and not ulx.url1.date then -- Title. No date. |
|||
sand = "[" .. ulx.url1.url .. " " .. ulx.url1.title .. "]" .. ulx.url1.tail |
|||
elseif ulx.url1.title and ulx.url1.date then -- Title. Date. |
|||
sand = "[" .. ulx.url1.url .. " " .. ulx.url1.title .. "]" .. ulx.url1.tail .. " (" .. indexstr .. " " .. ulx.url1.date .. ")" |
|||
else |
|||
return nil |
|||
end |
|||
if ulx.url1.extraurls > 0 then -- For multiple archive URLs |
|||
local tot = ulx.url1.extraurls + 1 |
|||
sand = sand .. period2 .. " Additional archives: " |
|||
for i=2,tot do |
|||
local indx = "url" .. i |
|||
if ulx[indx]["title"] then |
|||
displayfield = "title" |
|||
else |
|||
displayfield = "date" |
|||
end |
|||
sand = sand .. "[" .. ulx[indx]["url"] .. " " .. ulx[indx][displayfield] .. "]" |
|||
if i == tot then |
|||
sand = sand .. "." |
|||
else |
|||
sand = sand .. ", " |
|||
end |
|||
end |
|||
else |
|||
return sand |
|||
end |
|||
return sand |
|||
-- For {{cite archives}} |
|||
else |
|||
local function parameter_name_xlate (args, params, enum_params) |
|||
if ulx.url1.format == "addlarchives" then -- Multiple archive services |
|||
local name; -- holds modifiable name of the parameter name during evaluation |
|||
displayheader = "Additional archives: " |
|||
local enum; -- for enumerated parameters, holds the enumerator during evaluation |
|||
else -- Multiple pages from the same archive |
|||
local found = false; -- flag used to break out of nested for loops |
|||
displayheader = "Additional pages archived on " .. ulx.url1.date .. ": " |
|||
local new_args = {}; -- a table that holds canonical and translated parameter k/v pairs |
|||
end |
|||
local origin = {}; -- a table that maps original (local language) parameter names to their canonical name for local language error messaging |
|||
local tot = 1 + ulx.url1.extraurls |
|||
local unnamed_params; -- set true when unsupported positional parameters are detected |
|||
local sand = displayheader |
|||
for i=1,tot do |
|||
for k, v in pairs (args) do -- loop through all of the arguments in the args table |
|||
local indx = "url" .. i |
|||
name = k; -- copy of original parameter name |
|||
displayfield = ulx[indx]["title"] |
|||
if ulx.url1.format == "addlarchives" then |
|||
if not displayfield then |
|||
if non_western_digits then -- true when non-western digits supported at this wiki |
|||
displayfield = ulx[indx]["date"] |
|||
name = mw.ustring.gsub (name, '%d', digits); -- convert this wiki's non-western digits to western digits |
|||
end |
|||
else |
|||
if not displayfield then |
|||
enum = name:match ('%d+$'); -- get parameter enumerator if it exists; nil else |
|||
displayfield = "Page " .. i |
|||
end |
|||
if not enum then -- no enumerator so looking for non-enumnerated parameters |
|||
end |
|||
-- TODO: insert shortcut here? if params[name] then name holds the canonical parameter name; no need to search further |
|||
sand = sand .. "[" .. ulx[indx]["url"] .. " " .. displayfield .. "]" |
|||
for pname, aliases in pairs (params) do -- loop through each parameter the params table |
|||
if i == tot then |
|||
for _, alias in ipairs (aliases) do -- loop through each alias in the parameter's aliases table |
|||
sand = sand .. "." |
|||
if name == alias then |
|||
else |
|||
new_args[pname] = v; -- create a new entry in the new_args table |
|||
sand = sand .. ", " |
|||
origin [pname] = k; -- create an entry to make canonical parameter name to original local language parameter name |
|||
end |
|||
found = true; -- flag so that we can break out of these nested for loops |
|||
end |
|||
break; -- no need to search the rest of the aliases table for name so go on to the next k, v pair |
|||
return sand |
|||
end |
|||
end |
|||
if found then -- 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 |
|||
for pname, aliases in pairs (enum_params) do -- loop through each parameter the num_params table |
|||
for _, alias in ipairs (aliases) do -- loop through each alias in the parameter's aliases table |
|||
if name == alias then |
|||
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 |
|||
if found then -- 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 |
|||
return new_args, origin, unnamed_params; |
|||
end |
end |
||
function p.webarchive(frame) |
|||
args = frame.args |
|||
if (args[1]==nil) and (args["url"]==nil) then -- if no argument provided than check parent template/module args |
|||
args = frame:getParent().args |
|||
end |
|||
local tname = "Webarchive" -- name of calling template. Change if template rename. |
|||
ulx = {} -- Associative array to hold template data |
|||
track = {} -- Associative array to hold tracking categories |
|||
maxurls = 10 -- Max number of URLs allowed. |
|||
local verifydates = "yes" -- See documentation. Set "no" to disable. |
|||
-- URL argument (first) |
|||
--[[--------------------------< W E B A R C H I V E >---------------------------------------------------------- |
|||
local url1 = trimArg(args.url) or trimArg(args.url1) |
|||
template entry point |
|||
if not url1 then |
|||
return inlineError("url", "Empty.") .. createTracking() |
|||
end |
|||
if mw.ustring.find( url1, "https://web.http", 1, plain ) then -- track bug |
|||
track["Category:Webarchive template errors"] = 1 |
|||
return inlineError("url", "https://web.http") .. createTracking() |
|||
end |
|||
if url1 == "https://web.archive.org/http:/" then -- track bug |
|||
track["Category:Webarchive template errors"] = 1 |
|||
return inlineError("url", "Invalid URL") .. createTracking() |
|||
end |
|||
ulx.url1 = {} |
|||
]] |
|||
ulx.url1.url = url1 |
|||
local uri1 = mw.uri.new(ulx.url1.url) |
|||
ulx.url1.host = uri1.host |
|||
ulx.url1.extraurls = parseExtraArgs() |
|||
-- Nolink argument |
|||
local function webarchive(frame) |
|||
local args = getArgs (frame); |
|||
local nolink = trimArg2(args.nolink) |
|||
local data = 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; |
|||
if data.digits.enable then |
|||
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; |
|||
serviceName(uri1.host, nolink) |
|||
local origin = {}; -- holds a map of English to local language parameter names used in the current template; not currently used |
|||
local unnamed_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 |
|||
-- Date argument |
|||
local date, format, msg, udate, uri, url; |
|||
local ldf = 'iso'; -- when there is no |date= parameter, render url dates in iso format |
|||
if args.url and args.url1 then -- URL argument (first) |
|||
return inlineError (data.crit_err_msgs.conflicting, {origin.url, origin.url1}); |
|||
end |
|||
url = args.url or args.url1; |
|||
if not url then |
|||
return inlineError (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 |
|||
]] |
|||
local date = trimArg(args.date) or trimArg(args.date1) |
|||
if not (url:lower():find ('^http') or url:find ('^//')) then |
|||
if date == "*" and ulx.url1.service == "wayback" then |
|||
return inlineError (data.crit_err_msgs.invalid_url ); |
|||
date = "index" |
|||
end |
|||
elseif date and ulx.url1.service == "wayback" and verifydates == "yes" then |
|||
local ldf = dateFormat(date) |
|||
if ldf then |
|||
local udate = decodeWaybackDate( uri1.path, ldf ) |
|||
if udate ~= date then |
|||
date = udate .. inlineRed("<sup>[Date mismatch]</sup>", "warning") |
|||
end |
|||
end |
|||
elseif date and ulx.url1.service == "webcite" and verifydates == "yes" then |
|||
local ldf = dateFormat(date) |
|||
if ldf then |
|||
local udate = decodeWebciteDate( uri1.path, ldf ) |
|||
if udate == "query" then -- skip |
|||
elseif udate ~= date then |
|||
date = udate .. inlineRed("<sup>[Date mismatch]</sup>", "warning") |
|||
end |
|||
end |
|||
elseif not date and ulx.url1.service == "wayback" then |
|||
date = decodeWaybackDate( uri1.path, "iso" ) |
|||
if not date then |
|||
date = inlineRed("[Date error] (1)", "error") |
|||
end |
|||
elseif not date and ulx.url1.service == "webcite" then |
|||
date = decodeWebciteDate( uri1.path, "iso" ) |
|||
if date == "query" then |
|||
date = inlineRed("[Date missing]", "warning") |
|||
elseif not date then |
|||
date = inlineRed("[Date error] (1)", "error") |
|||
end |
|||
elseif not date then |
|||
date = inlineRed("[Date missing]", "warning") |
|||
end |
|||
ulx.url1.date = date |
|||
-- Format argument |
|||
ulx.url1 = {} |
|||
ulx.url1.url = url |
|||
local format = trimArg(args.format) |
|||
ulx.url1.extraurls = parseExtraArgs(args) |
|||
if not format then |
|||
format = "none" |
|||
else |
|||
if format == "addlpages" then |
|||
if not ulx.url1.date then |
|||
format = "none" |
|||
end |
|||
elseif format == "addlarchives" then |
|||
format = "addlarchives" |
|||
else |
|||
format = "none" |
|||
end |
|||
end |
|||
ulx.url1.format = format |
|||
-- Title argument |
|||
local good = 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 |
|||
if not good or nil == uri.host then -- abandon when ulx.url1.url is malformed |
|||
return inlineError (data.crit_err_msgs.invalid_url); |
|||
end |
|||
serviceName(uri.host, args.nolink) |
|||
local title = trimArg(args.title) or trimArg(args.title1) |
|||
if args.date and args.date1 then -- Date argument |
|||
ulx.url1.title = title |
|||
return inlineError (data.crit_err_msgs.conflicting, {origin.date, origin.date1}); |
|||
end |
|||
date = args.date or args.date1; |
|||
date = date and date:gsub (' +', ' '); -- replace multiple spaces with a single space |
|||
local rend = createRendering() |
|||
if date and config.verifydates then |
|||
if not rend then |
|||
rend = '<span style="font-size:100%" class="error citation-comment">Error in [[:टेम्पलेट:' .. tname .. ']]: Unknown problem. Please report on template talk page.</span>' |
|||
date = 'index'; |
|||
track["श्रेणी:Webarchive template errors"] = 1 |
|||
ldf = 'iso'; -- set to default format |
|||
end |
|||
else |
|||
date, ldf = decode_date (date); -- get an iso format date from date and get date's original format |
|||
end |
|||
end |
|||
return rend .. createTracking() |
|||
if 'wayback' == ulx.url1.service or 'locwebarchives' == ulx.url1.service then |
|||
if date then |
|||
if config.verifydates then |
|||
if ldf then |
|||
udate, msg = decodeWaybackDate (uri.path); -- get the url date in iso format and format of date in |date=; 'index' when wayback url date is * |
|||
if not udate then -- this is the only 'fatal' error return |
|||
return inlineError (data.crit_err_msgs[msg]); |
|||
end |
|||
if udate ~= date then -- 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); |
|||
if not udate then -- this is the only 'fatal' error return |
|||
return inlineError (data.crit_err_msgs[msg]); |
|||
end |
|||
if '' == udate then |
|||
date = nil; -- unset |
|||
else |
|||
date = udate; |
|||
end |
|||
end |
|||
elseif 'webcite' == ulx.url1.service then |
|||
if date then |
|||
if config.verifydates then |
|||
if ldf then |
|||
udate = decodeWebciteDate (uri.path); -- get the url date in iso format |
|||
if 'query' ~= udate then -- skip if query |
|||
if udate ~= date then -- 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" ) |
|||
if date == "query" then |
|||
date = nil; -- unset |
|||
msg = inlineRed (err_warn_msgs.date_miss, 'warning'); |
|||
elseif not date then -- invalid base62 string |
|||
date = inlineRed (err_warn_msgs.date1, 'error'); |
|||
end |
|||
end |
|||
elseif 'archiveis' == ulx.url1.service then |
|||
if date then |
|||
if config.verifydates then |
|||
if ldf then |
|||
udate, msg = decodeArchiveisDate (uri.path) -- get the url date in iso format |
|||
if 'short link' ~= udate then -- skip if short link |
|||
if udate ~= date then -- 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" ) |
|||
if udate == "short link" then |
|||
date = nil; -- unset |
|||
msg = inlineRed (err_warn_msgs.date_miss, 'warning'); |
|||
elseif '' == udate then |
|||
date = nil; -- unset |
|||
else |
|||
date = udate; |
|||
end |
|||
end |
|||
else -- some other service |
|||
if not date then |
|||
msg = inlineRed (err_warn_msgs.date_miss, 'warning'); |
|||
end |
|||
end |
|||
if 'index' == date then |
|||
ulx.url1.date = date .. (msg or ''); -- create index + message (if there is one) |
|||
elseif date then |
|||
ulx.url1.date = makeDate (date, nil, nil, ldf) .. (msg or ''); -- 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 |
|||
if not format then |
|||
format = "none" |
|||
else |
|||
for k, v in pairs (data.format_vals) do -- |format= accepts two specific values loop through a table of those values |
|||
local found; -- declare a nil flag |
|||
for _, p in ipairs (v) do -- loop through local language variants |
|||
if format == p then -- 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 |
|||
if found then |
|||
break; |
|||
end |
|||
end |
|||
if format == "addlpages" then |
|||
if not ulx.url1.date then |
|||
format = "none" |
|||
end |
|||
elseif format == "addlarchives" then |
|||
format = "addlarchives" |
|||
else |
|||
format = "none" |
|||
end |
|||
end |
|||
ulx.url1.format = format |
|||
if args.title and args.title1 then -- Title argument |
|||
return inlineError (data.crit_err_msgs.conflicting, {origin.title, origin.title1}); |
|||
end |
|||
ulx.url1.title = args.title or args.title1; |
|||
local rend = createRendering() |
|||
if not rend then |
|||
return inlineError (data.crit_err_msgs.unknown); |
|||
end |
|||
return rend .. ((unnamed_params and inlineRed (err_warn_msgs.unnamed_params, 'warning')) or '') .. createTracking(); |
|||
end |
end |
||
return p |
|||
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------ |
|||
]] |
|||
return {webarchive = webarchive}; |
१०:२६, १२ जुलाई २०२० कय समय कय अवतरण
--[[--------------------------< C O N F I G U R A T I O N >----------------------------------------------------
global configuration settings
]]
local config = { maxurls = 10, -- Max number of URLs allowed. tname = 'Webarchive', -- name of calling template. Change if template rename. verifydates = true, -- See documentation. Set false to disable. }
--[[--------------------------< U N C A T E G O R I Z E D _ N A M E S P A C E S >------------------------------
List of namespaces that should not be included in citation error categories.
Note: Namespace names should use underscores instead of spaces.
]]
local uncategorized_namespaces = { -- same list as specified at Module:Citation/CS1/Configuration ['User']=true, ['Talk']=true, ['User_talk']=true, ['Wikipedia_talk']=true, ['File_talk']=true, ['Template_talk']=true, ['Help_talk']=true, ['Category_talk']=true, ['Portal_talk']=true, ['Book_talk']=true, ['Draft_talk']=true, ['Education_Program_talk']=true, ['Module_talk']=true, ['MediaWiki_talk']=true, }
local uncategorized_subpages = {'/[Ss]andbox', '/[Tt]estcases'}; -- list of Lua patterns found in page names of pages we should not categorize
local excepted_pages = { -- these pages will be categorized if set true; set to nil to disable ['Module talk:Webarchive/testcases'] = true, -- test cases pages used during development ['Template:Webarchive/testcases/Production'] = true, }
--[[--------------------------< C A T E G O R I E S >----------------------------------------------------------
this is a table of all categories supported by Module:Webarchive
]]
local categories = { archiveis = 'Category:Webarchive template archiveis links', error = 'Category:Webarchive template errors', other = 'Category:Webarchive template other archives', unknown = 'Category:Webarchive template unknown archives', warning = 'Category:Webarchive template warnings', wayback = 'Category:वेबग्रंथागार साँचा वेबैक कड़ियाँ', webcite = 'Category:Webarchive template webcite links', }
--[[--------------------------< P R E F I X E S >--------------------------------------------------------------
used only with serviceName(), this table holds the two generic tail-text prefixes specified by services['<service name>'][1]
]]
local prefixes = { at = 'at', atthe = 'at the', }
--[=[-------------------------< S E R V I C E S >--------------------------------------------------------------
this is a table of tables for archive services. Each service table has: [1]=prefix; may be boolean true or false, or text string where: true indicates that the prefix is taken from prefixes.atthe false indicates that the prefix is taken from prefixes.at 'text string' is used in lieu of the typical 'at' or 'at the' prefix [2]=wikilink target article that describes the service; set to nil if not used [3]=wikilink label; the label in label; set to nil if not used; when there is not article ([2] is nil) use this to name the service; see wikiwix in the table [4]=service ID; set to nil if not used [5]=tracking category key from the categories table; set to nil if not used [6]=postfix; text string to be appended at the end of the tail string - see webarchive.loc.gov in the table
]=]
local services = { ['archive.is'] = {false, 'Archive.is', nil, 'archiveis', categories.archiveis}, ['archive.ec'] = {false, 'Archive.is', nil, 'archiveis', categories.archiveis}, ['archive.fo'] = {false, 'Archive.is', nil, 'archiveis', categories.archiveis}, ['archive.li'] = {false, 'Archive.is', nil, 'archiveis', categories.archiveis}, ['archive.org'] = {true, 'वेबैक मशीन', nil, 'wayback', categories.wayback}, ['archive.today'] = {false, 'Archive.is', nil, 'archiveis', categories.archiveis}, ['archive-it.org'] = {false, 'Archive-It', nil, 'archiveit'}, ['arquivo.pt'] = {true, nil, 'Portuguese Web Archive'}, ['bibalex.org'] = {false, 'Bibliotheca Alexandrina#Internet Archive partnership', 'Bibliotheca Alexandrina'}, ['collectionscanada'] = {true, 'Canadian Government Web Archive'}, ['europarchive.org'] = {true, 'National Library of Ireland'}, ['freezepage.com'] = {false, nil, 'Freezepage'}, ['haw.nsk'] = {true, 'Croatian Web Archive (HAW)'}, ['langzeitarchivierung.bib-bvb.de'] = {false, 'Bavarian State Library'}, ['loc.gov'] = {true, 'Library of Congress'}, ['nationalarchives.gov.uk'] = {true, 'UK Government Web Archive'}, ['nlb.gov.sg'] = {false, 'Web Archive Singapore'}, ['pandora.nla.gov.au'] = {false, 'Pandora Archive'}, ['parliament.uk'] = {true, 'UK Parliament\'s Web Archive'}, ['perma.cc'] = {false, 'Perma.cc'}, ['perma-archives.cc'] = {false, 'Perma.cc'}, ['proni.gov'] = {true, 'Public Record Office of Northern Ireland'}, ['screenshots.com'] = {false, nil, 'Screenshots'}, ['stanford.edu'] = {true, 'Stanford University Libraries', 'Stanford Web Archive'}, ['timetravel.mementoweb.org'] = {false, 'Memento Project'}, ['uni-lj.si'] = {true, nil, 'Slovenian Web Archive'}, ['veebiarhiiv.digar.ee'] = {true, nil, 'Estonian Web Archive'}, ['vefsafn.is'] = {true, 'National and University Library of Iceland'}, ['webarchive.bac-lac.gc.ca'] = {false, 'Library and Archives Canada'}, ['webarchive.loc.gov'] = {true, 'Library of Congress', nil, 'locwebarchives', nil, 'Web Archives'}, ['webarchive.org.uk'] = {true, 'UK Web Archive'}, ['webcache.googleusercontent.com'] = {false, nil, 'Google Cache'}, ['webcitation.org'] = {false, 'WebCite', nil, 'webcite', categories.webcite}, ['webharvest.gov'] = {true, 'National Archives and Records Administration'}, ['webrecorder.io'] = {false, 'webrecorder.io'}, ['wikiwix.com'] = {false, nil, 'Wikiwix'}, ['yorku.ca'] = {false, 'York University Libraries', 'York University Digital Library'}, }
--[[--------------------------< S T A T I C T E X T >--------------------------------------------------------
for internationalzation
]]
local s_text = { addlarchives = 'Additional archives', addlpages = 'Additional pages archived on', -- TODO why the there? replace with regular space? Archive_index = 'Archive index', Archived = 'Archived', archived = 'archived', archive = 'archive', Page = 'Page', }
--[[--------------------------< E R R _ W A R N _ M S G S >----------------------------------------------------
these tables hold error and warning message text
]]
local err_warn_msgs = { date_err = '[Date error]', -- decodeWebciteDate, decodeWaybackDate, decodeArchiveisDate date_miss = '[Date missing]', -- parseExtraArgs ts_short = '[Timestamp date length]', -- decodeWaybackDate timestamp less than 8 digits ts_date = '[Timestamp date invalid]', -- decodeWaybackDate timestamp not a valid date unknown_url = '[Error: unknown archive URL]', -- serviceName unnamed_params = '[Positional parameters ignored]',
--warnings mismatch = '[Date mismatch]', -- webarchive ts_len = '[Timestamp length]', -- decodeWaybackDate, decodeArchiveisDate timestamp not 14 digits ts_cal = '[Calendar]', -- decodeWaybackDate timestamp has trailing splat }
local crit_err_msgs = { -- critical error messages
conflicting = 'Conflicting |$1= and |$2=',
empty = 'Empty url',
-- iabot1 = 'https://web.http', -- TODO: these iabot bugs perportedly fixed; removing these causes lua script error
-- iabot2 = 'Invalid URL', -- at Template:Webarchive/testcases/Production; resolve that before deleting these messages
invalid_url = 'Invalid URL',
ts_nan = 'Timestamp not a number',
unknown = 'Unknown problem. Please report on template talk page',
}
--[[--------------------------< D A T E I N T E R N A T I O N A L I Z A T I O N >----------------------------
these tables hold data that is used when converting date formats from non-English languages (because mw.language.getContentLanguage:formatDate() doesn't understand non-English month names)
]]
local month_num = { -- retain English language names even though they may not be strictly required on the local wiki -- from enwiki ['January'] = 1, ['February'] = 2, ['March'] = 3, ['April'] = 4, ['May'] = 5, ['June'] = 6, ['July'] = 7, ['August'] = 8, ['September'] = 9, ['October'] = 10, ['November'] = 11, ['December'] = 12, ['Jan'] = 1, ['Feb'] = 2, ['Mar'] = 3, ['Apr'] = 4, ['May'] = 5, ['Jun'] = 6, ['Jul'] = 7, ['Aug'] = 8, ['Sep'] = 9, ['Oct'] = 10, ['Nov'] = 11, ['Dec'] = 12, -- for hiwiki
['जनवरी'] = 1, ['फ़रवरी'] = 2, ['फरवरी'] = 2, ['मार्च'] = 3, ['अप्रैल'] = 4, ['मई'] = 5, ['जून'] = 6, ['जुलाई'] = 7, ['अगस्त'] = 8, ['सितम्बर'] = 9, ['अक्टूबर'] = 10, ['नवम्बर'] = 11, ['दिसम्बर'] = 12, ['सितंबर'] = 9, ['अक्तूबर'] = 10, ['नवंबर'] = 11, ['दिसंबर'] = 12,
-- add local wiki month-names to number translation here -- [] = 1, [] = 2, [] = 3, [] = 4, [] = 5, [] = 6, [] = 7, [] = 8, [] = 9, [] = 10, [] = 11, [] = 12, };
-- when the local wiki uses non-western digits in dates, local wiki digits must be -- translated to western digits; lua only understands western digits local digits = { -- use this table to aid translation -- [] = 0, [] = 1, [] = 2, [] = 3, [] = 4, [] = 5, [] = 6, [] = 7, [] = 8, [] = 9, -- fill these table indexes with local digits enable = false -- set to true to enable local-digit to western-digit translation };
--[[--------------------------< P A R A M E T E R I N T E R N A T I O N A L I Z A T I O N >------------------
this table holds tables of parameter names and their non-English aliases. In the enum_params table '#' is a single character placeholder for 1 or more digit characters
parameter names in this table shall be lowercase ]]
local params = { ['url'] = {'url'}, ['date'] = {'date', 'datum'}, ['title'] = {'title', 'titel'}, ['nolink'] = {'nolink'}, ['format'] = {'format'} }
local enum_params = { ['url#'] = {'url#'}, ['date#'] = {'date#', 'datum#'}, ['title#'] = {'title#', 'titel#'}, }
local format_vals = { -- |format= accepts two values; add local language variants here ['addlpages'] = {'addlpages'}, ['addlarchives'] = {'addlarchives'}, }
--[[--------------------------< E X P O R T E D T A B L E S >------------------------------------------------
]]
return { categories = categories, config = config, crit_err_msgs = crit_err_msgs, digits = digits, enum_params = enum_params, err_warn_msgs = err_warn_msgs, excepted_pages = excepted_pages, format_vals = format_vals, month_num = month_num, params = params, prefixes = prefixes, services = services, s_text = s_text, uncategorized_namespaces = uncategorized_namespaces, uncategorized_subpages = uncategorized_subpages, }
--[[ ----------------------------------
Lua module implementing the {{webarchive}} template.
A merger of the functionality of three templates: {{wayback}}, {{webcite}} and {{cite archives}}
]]
local p = {}
--[[--------------------------< inlineError >-----------------------
Critical error. Render output completely in red. Add to tracking category.
]]
local function inlineError(arg, msg)
track["श्रेणी:वेबआर्काइव टेम्पलेट खराबी"] = 1
return '<span style="font-size:100%" class="error citation-comment">Error in webarchive template: Check <code style="color:inherit; border:inherit; padding:inherit;">|' .. arg .. '=</code> value. ' .. msg .. '</span>'
end
--[[--------------------------< inlineRed >-----------------------
Render a text fragment in red, such as a warning as part of the final output.
Add tracking category.
]]
local function inlineRed(msg, trackmsg)
if trackmsg == "warning" then
track["श्रेणी:वेबआर्काइव टेम्पलेट चेतावनी"] = 1
elseif trackmsg == "error" then
track["श्रेणी:वेबआर्काइव टेम्पलेटखराबी"] = 1
end
return '<span style="font-size:100%" class="error citation-comment">' .. msg .. '</span>'
end
--[[--------------------------< trimArg >-----------------------
trimArg returns nil if arg is "" while trimArg2 returns 'true' if arg is ""
trimArg2 is for args that might accept an empty value, as an on/off switch like nolink=
]]
local function trimArg(arg)
if arg == "" or arg == nil then
return nil
else
return mw.text.trim(arg)
end
end
local function trimArg2(arg)
if arg == nil then
return nil
else
return mw.text.trim(arg)
end
end
--[[--------------------------< base62 >-----------------------
Convert base-62 to base-10
Credit: https://de.wikipedia.org/wiki/Modul:Expr
]]
local function base62( value )
local r = 1
if value:match( "^%w+$" ) then
local n = #value
local k = 1
local c
r = 0
for i = n, 1, -1 do
c = value:byte( i, i )
if c >= 48 and c <= 57 then
c = c - 48
elseif c >= 65 and c <= 90 then
c = c - 55
elseif c >= 97 and c <= 122 then
c = c - 61
else -- How comes?
r = 1
break -- for i
end
r = r + c * k
k = k * 62
end -- for i
end
return r
end
--[[--------------------------< tableLength >-----------------------
Given a 1-D table, return number of elements
]]
local function tableLength(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
--[[--------------------------< dateFormat >-----------------------
Given a date string, return its format: dmy, mdy, iso, ymd
If unable to determine return nil
]]
local function dateFormat(date)
local dt = {}
dt.split = {}
dt.split = mw.text.split(date, "-")
if tableLength(dt.split) == 3 then
if tonumber(dt.split[1]) > 1900 and tonumber(dt.split[1]) < 2200 and tonumber(dt.split[2]) and tonumber(dt.split[3]) then
return "iso"
else
return nil
end
end
dt.split = mw.text.split(date, " ")
if tableLength(dt.split) == 3 then
if tonumber(dt.split[3]) then
if tonumber(dt.split[3]) > 1900 and tonumber(dt.split[3]) < 2200 then
if tonumber(dt.split[1]) then
return "dmy"
else
return "mdy"
end
else
if tonumber(dt.split[1]) then
if tonumber(dt.split[1]) > 1900 and tonumber(dt.split[1]) < 2200 then
return "ymd"
end
end
end
end
end
return nil
end
--[[--------------------------< makeDate >-----------------------
Given a zero-padded 4-digit year, 2-digit month and 2-digit day, return a full date in df format
df = mdy, dmy, iso, ymd
]]
local function makeDate(year, month, day, df)
if not year or year == "" or not month or month == "" or not day or day == "" then
return nil
end
local zmonth = month -- month with leading 0
month = month:match("0*(%d+)") -- month without leading 0
if tonumber(month) < 1 or tonumber(month) > 12 then
return year
end
local nmonth = os.date("%B", os.time{year=2000, month=month, day=1} ) -- month in name form
if not nmonth then
return year
end
local zday = day
day = zday:match("0*(%d+)")
if tonumber(day) < 1 or tonumber(day) > 31 then
if df == "mdy" or df == "dmy" then
return nmonth .. " " .. year
elseif df == "iso" then
return year .. "-" .. zmonth
elseif df == "ymd" then
return year .. " " .. nmonth
else
return nmonth .. " " .. year
end
end
if df == "mdy" then
return nmonth .. " " .. day .. ", " .. year -- September 1, 2016
elseif df == "dmy" then
return day .. " " .. nmonth .. " " .. year -- 1 September 2016
elseif df == "iso" then
return year .. "-" .. zmonth .. "-" .. zday -- 2016-09-01
elseif df == "ymd" then
return year .. " " .. nmonth .. " " .. cday -- 2016 September 1
else
return nmonth .. " " .. day .. ", " .. year -- September 1, 2016
end
end
--[[--------------------------< decodeWebciteDate >-----------------------
Given a URI-path to Webcite (eg. /67xHmVFWP) return the encoded date in df format
]]
local function decodeWebciteDate(path, df)
local dt = {}
dt.split = {}
dt.split = mw.text.split(path, "/")
-- valid URL formats that are not base62
-- http://www.webcitation.org/query?id=1138911916587475
-- http://www.webcitation.org/1138911916587475
-- http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e
if dt.split[2] == "query" or dt.split[2] == "cache" or tonumber(dt.split[2]) then
return "query"
end
dt.full = os.date("%Y %m %d", string.sub(string.format("%d", base62(dt.split[2])),1,10) )
dt.split = mw.text.split(dt.full, " ")
dt.year = dt.split[1]
dt.month = dt.split[2]
dt.day = dt.split[3]
if not tonumber(dt.year) or not tonumber(dt.month) or not tonumber(dt.day) then
return inlineRed("[Date error] (1)", "error")
end
if tonumber(dt.month) > 12 or tonumber(dt.day) > 31 or tonumber(dt.month) < 1 then
return inlineRed("[Date error] (2)", "error")
end
if tonumber(dt.year) > tonumber(os.date("%Y")) or tonumber(dt.year) < 1900 then
return inlineRed("[Date error] (3)", "error")
end
fulldate = makeDate(dt.year, dt.month, dt.day, df)
if not fulldate then
return inlineRed("[Date error] (4)", "error")
else
return fulldate
end
end
--[[--------------------------< snapDateToString >-----------------------
Given a URI-path to Wayback (eg. /web/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 "*"
]]
local function decodeWaybackDate(path, df)
local snapdate, snapdatelong, currdate, fulldate
local safe = path
snapdate = string.gsub(safe, "^/w?e?b?/?", "") -- Remove leading "/web/" or "/"
safe = snapdate
local N = mw.text.split(safe, "/")
snapdate = N[1]
if snapdate == "*" then -- eg. /web/*/http..
return "index"
end
safe = snapdate
snapdate = string.gsub(safe, "[a-z][a-z]_[0-9]?$", "") -- Remove any trailing "re_" from date
safe = snapdate
snapdate = string.gsub(safe, "[-]", "") -- Remove dashes from date eg. 2015-01-01
safe = snapdate
snapdate = string.gsub(safe, "[*]$", "") -- Remove trailing "*"
if not tonumber(snapdate) then
return inlineRed("[Date error] (2)", "error")
end
local dlen = string.len(snapdate)
if dlen < 4 then
return inlineRed("[Date error] (3)", "error")
end
if dlen < 14 then
snapdatelong = snapdate .. string.rep("0", 14 - dlen)
else
snapdatelong = snapdate
end
local year = string.sub(snapdatelong, 1, 4)
local month = string.sub(snapdatelong, 5, 6)
local day = string.sub(snapdatelong, 7, 8)
if not tonumber(year) or not tonumber(month) or not tonumber(day) then
return inlineRed("[Date error] (4)", "error")
end
if tonumber(month) > 12 or tonumber(day) > 31 or tonumber(month) < 1 then
return inlineRed("[Date error] (5)", "error")
end
currdate = os.date("%Y")
if tonumber(year) > tonumber(currdate) or tonumber(year) < 1900 then
return inlineRed("[Date error] (6)", "error")
end
fulldate = makeDate(year, month, day, df)
if not fulldate then
return inlineRed("[Date error] (7)", "error")
else
return fulldate
end
end
--[[--------------------------< serviceName >-----------------------
Given a domain extracted by mw.uri.new() (eg. web.archive.org) set tail string and service ID
]]
local function serviceName(host, nolink)
local tracking = "श्रेणी:वेबआर्काइव टेम्पलेट अन्य आर्काइव"
local bracketopen = "[["
local bracketclose = "]]"
if nolink then
bracketopen = ""
bracketclose = ""
end
ulx.url1.service = "other"
ulx.url1.tail = " at " .. ulx.url1.host .. " " .. inlineRed("Error: unknown archive URL")
if mw.ustring.find( host, "archive.org", 1, plain ) then
ulx.url1.service = "wayback"
ulx.url1.tail = bracketopen .. " वेबैक मशीन" .. bracketclose .." पर "
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट वेबैक कड़ी"
elseif mw.ustring.find( host, "webcitation.org", 1, plain ) then
ulx.url1.service = "webcite"
ulx.url1.tail = bracketopen .. "WebCite" .. bracketclose .." पर "
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट वेबसाइट कड़ी"
elseif mw.ustring.find( host, "archive.is", 1, plain ) then
ulx.url1.service = "archiveis"
ulx.url1.tail = bracketopen .. " आर्काइव.इज" .. bracketclose .. " पर "
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट आर्काइवइज कड़ी"
elseif mw.ustring.find( host, "archive.fo", 1, plain ) then
ulx.url1.service = "archiveis"
ulx.url1.tail = " at " .. bracketopen .. "Archive.is" .. bracketclose
tracking = "श्रेणी:Webarchive template archiveis links"
elseif mw.ustring.find( host, "archive.today", 1, plain ) then
ulx.url1.service = "archiveis"
ulx.url1.tail = " at " .. bracketopen .. "Archive.is" .. bracketclose
tracking = "श्रेणी:Webarchive template archiveis links"
elseif mw.ustring.find( host, "archive[-]it.org", 1, plain ) then
ulx.url1.service = "archiveit"
ulx.url1.tail = " at " .. bracketopen .. "Archive-It" .. bracketclose
elseif mw.ustring.find( host, "arquivo.pt", 1, plain) then
ulx.url1.tail = " at the " .. "Portuguese Web Archive"
elseif mw.ustring.find( host, "loc.gov", 1, plain ) then
ulx.url1.tail = " at the " .. bracketopen .. "Library of Congress" .. bracketclose
elseif mw.ustring.find( host, "webharvest.gov", 1, plain ) then
ulx.url1.tail = " at the " .. bracketopen .. "National Archives and Records Administration" .. bracketclose
elseif mw.ustring.find( host, "bibalex.org", 1, plain ) then
ulx.url1.tail = " at " .. "[[Bibliotheca_Alexandrina#Internet_Archive_partnership|Bibliotheca Alexandrina]]"
elseif mw.ustring.find( host, "collectionscanada", 1, plain ) then
ulx.url1.tail = " at the " .. "Canadian Government Web Archive"
elseif mw.ustring.find( host, "haw.nsk", 1, plain ) then
ulx.url1.tail = " at the " .. "Croatian Web Archive (HAW)"
elseif mw.ustring.find( host, "veebiarhiiv.digar.ee", 1, plain ) then
ulx.url1.tail = " at the " .. "Estonian Web Archive"
elseif mw.ustring.find( host, "vefsafn.is", 1, plain ) then
ulx.url1.tail = " at the " .. "[[National and University Library of Iceland]]"
elseif mw.ustring.find( host, "proni.gov", 1, plain ) then
ulx.url1.tail = " at the " .. bracketopen .. "Public Record Office of Northern Ireland" .. bracketclose
elseif mw.ustring.find( host, "uni[-]lj.si", 1, plain ) then
ulx.url1.tail = " at the " .. "Slovenian Web Archive"
elseif mw.ustring.find( host, "stanford.edu", 1, plain ) then
ulx.url1.tail = " at the " .. "[[Stanford University Libraries|Stanford Web Archive]]"
elseif mw.ustring.find( host, "nationalarchives.gov.uk", 1, plain ) then
ulx.url1.tail = " at the " .. bracketopen .. "UK Government Web Archive" .. bracketclose
elseif mw.ustring.find( host, "parliament.uk", 1, plain ) then
ulx.url1.tail = " at the " .. bracketopen .. "UK Parliament's Web Archive" .. bracketclose
elseif mw.ustring.find( host, "webarchive.org.uk", 1, plain ) then
ulx.url1.tail = " at the " .. bracketopen .. "UK Web Archive" .. bracketclose
elseif mw.ustring.find( host, "nlb.gov.sg", 1, plain ) then
ulx.url1.tail = " at " .. "Web Archive Singapore"
elseif mw.ustring.find( host, "pandora.nla.gov.au", 1, plain ) then
ulx.url1.tail = " at " .. bracketopen .. "Pandora Archive" .. bracketclose
elseif mw.ustring.find( host, "screenshots.com", 1, plain ) then
ulx.url1.tail = " at " .. "Screenshots"
elseif mw.ustring.find( host, "wikiwix.com", 1, plain ) then
ulx.url1.tail = " विकिविक्स" .. " पर "
elseif mw.ustring.find( host, "perma.cc", 1, plain ) then
ulx.url1.tail = " at " .. bracketopen .. "Perma.cc" .. bracketclose
else
tracking = "श्रेणी:वेबआर्काइव टेम्पलेट नामालूम आर्काइव"
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")
]]
local function parseExtraArgs()
local i, j, argurl, argurl2, argdate, argtitle
j = 2
for i = 2, maxurls do
argurl = "url" .. i
if trimArg(args[argurl]) then
argurl2 = "url" .. j
ulx[argurl2] = {}
ulx[argurl2]["url"] = args[argurl]
argdate = "date" .. j
if trimArg(args[argdate]) then
ulx[argurl2]["date"] = args[argdate]
else
ulx[argurl2]["date"] = inlineRed("[Date missing]", "warning")
end
argtitle = "title" .. j
if trimArg(args[argtitle]) then
ulx[argurl2]["title"] = args[argtitle]
else
ulx[argurl2]["title"] = nil
end
j = j + 1
end
end
if j == 2 then
return 0
else
return j - 2
end
end
--[[--------------------------< comma >-----------------------
Given a date string, return "," if it's MDY
]]
local function comma(date)
local N = mw.text.split(date, " ")
local O = mw.text.split(N[1], "-") -- for ISO
if O[1] == "index" then return "" end
if not tonumber(O[1]) then
return ","
else
return ""
end
end
--[[--------------------------< createTracking >-----------------------
Return data in track[] ie. tracking categories
]]
local function createTracking()
local sand = ""
if tableLength(track) > 0 then
for key,_ in pairs(track) do
sand = sand .. "[[" .. key .. "]]"
end
end
return sand
end
--[[--------------------------< createRendering >-----------------------
Return a rendering of the data in ulx[][]
]]
local function createRendering()
local sand, displayheader, displayfield
local period1 = "" -- For backwards compat with {{wayback}}
local period2 = "."
local indexstr = "archived"
if ulx.url1.date == "index" then
indexstr = "archive"
end
-- For {{wayback}}, {{webcite}}
if ulx.url1.format == "none" then
if not ulx.url1.title and not ulx.url1.date then -- No title. No date
sand = "[" .. ulx.url1.url .. " Archived]" .. ulx.url1.tail
elseif not ulx.url1.title and ulx.url1.date then -- No title. Date.
if ulx.url1.service == "wayback" then
period1 = "."
period2 = ""
end
sand = "[" .. ulx.url1.url .. " Archived] " .. ulx.url1.date .. comma(ulx.url1.date) .. ulx.url1.tail .. period1
elseif ulx.url1.title and not ulx.url1.date then -- Title. No date.
sand = "[" .. ulx.url1.url .. " " .. ulx.url1.title .. "]" .. ulx.url1.tail
elseif ulx.url1.title and ulx.url1.date then -- Title. Date.
sand = "[" .. ulx.url1.url .. " " .. ulx.url1.title .. "]" .. ulx.url1.tail .. " (" .. indexstr .. " " .. ulx.url1.date .. ")"
else
return nil
end
if ulx.url1.extraurls > 0 then -- For multiple archive URLs
local tot = ulx.url1.extraurls + 1
sand = sand .. period2 .. " Additional archives: "
for i=2,tot do
local indx = "url" .. i
if ulx[indx]["title"] then
displayfield = "title"
else
displayfield = "date"
end
sand = sand .. "[" .. ulx[indx]["url"] .. " " .. ulx[indx][displayfield] .. "]"
if i == tot then
sand = sand .. "."
else
sand = sand .. ", "
end
end
else
return sand
end
return sand
-- For {{cite archives}}
else
if ulx.url1.format == "addlarchives" then -- Multiple archive services
displayheader = "Additional archives: "
else -- Multiple pages from the same archive
displayheader = "Additional pages archived on " .. ulx.url1.date .. ": "
end
local tot = 1 + ulx.url1.extraurls
local sand = displayheader
for i=1,tot do
local indx = "url" .. i
displayfield = ulx[indx]["title"]
if ulx.url1.format == "addlarchives" then
if not displayfield then
displayfield = ulx[indx]["date"]
end
else
if not displayfield then
displayfield = "Page " .. i
end
end
sand = sand .. "[" .. ulx[indx]["url"] .. " " .. displayfield .. "]"
if i == tot then
sand = sand .. "."
else
sand = sand .. ", "
end
end
return sand
end
end
function p.webarchive(frame)
args = frame.args
if (args[1]==nil) and (args["url"]==nil) then -- if no argument provided than check parent template/module args
args = frame:getParent().args
end
local tname = "Webarchive" -- name of calling template. Change if template rename.
ulx = {} -- Associative array to hold template data
track = {} -- Associative array to hold tracking categories
maxurls = 10 -- Max number of URLs allowed.
local verifydates = "yes" -- See documentation. Set "no" to disable.
-- URL argument (first)
local url1 = trimArg(args.url) or trimArg(args.url1)
if not url1 then
return inlineError("url", "Empty.") .. createTracking()
end
if mw.ustring.find( url1, "https://web.http", 1, plain ) then -- track bug
track["Category:Webarchive template errors"] = 1
return inlineError("url", "https://web.http") .. createTracking()
end
if url1 == "https://web.archive.org/http:/" then -- track bug
track["Category:Webarchive template errors"] = 1
return inlineError("url", "Invalid URL") .. createTracking()
end
ulx.url1 = {}
ulx.url1.url = url1
local uri1 = mw.uri.new(ulx.url1.url)
ulx.url1.host = uri1.host
ulx.url1.extraurls = parseExtraArgs()
-- Nolink argument
local nolink = trimArg2(args.nolink)
serviceName(uri1.host, nolink)
-- Date argument
local date = trimArg(args.date) or trimArg(args.date1)
if date == "*" and ulx.url1.service == "wayback" then
date = "index"
elseif date and ulx.url1.service == "wayback" and verifydates == "yes" then
local ldf = dateFormat(date)
if ldf then
local udate = decodeWaybackDate( uri1.path, ldf )
if udate ~= date then
date = udate .. inlineRed("<sup>[Date mismatch]</sup>", "warning")
end
end
elseif date and ulx.url1.service == "webcite" and verifydates == "yes" then
local ldf = dateFormat(date)
if ldf then
local udate = decodeWebciteDate( uri1.path, ldf )
if udate == "query" then -- skip
elseif udate ~= date then
date = udate .. inlineRed("<sup>[Date mismatch]</sup>", "warning")
end
end
elseif not date and ulx.url1.service == "wayback" then
date = decodeWaybackDate( uri1.path, "iso" )
if not date then
date = inlineRed("[Date error] (1)", "error")
end
elseif not date and ulx.url1.service == "webcite" then
date = decodeWebciteDate( uri1.path, "iso" )
if date == "query" then
date = inlineRed("[Date missing]", "warning")
elseif not date then
date = inlineRed("[Date error] (1)", "error")
end
elseif not date then
date = inlineRed("[Date missing]", "warning")
end
ulx.url1.date = date
-- Format argument
local format = trimArg(args.format)
if not format then
format = "none"
else
if format == "addlpages" then
if not ulx.url1.date then
format = "none"
end
elseif format == "addlarchives" then
format = "addlarchives"
else
format = "none"
end
end
ulx.url1.format = format
-- Title argument
local title = trimArg(args.title) or trimArg(args.title1)
ulx.url1.title = title
local rend = createRendering()
if not rend then
rend = '<span style="font-size:100%" class="error citation-comment">Error in [[:टेम्पलेट:' .. tname .. ']]: Unknown problem. Please report on template talk page.</span>'
track["श्रेणी:Webarchive template errors"] = 1
end
return rend .. createTracking()
end
return p