وحدة:Webarchive: الفرق بين النسختين
[نسخة منشورة] | [نسخة منشورة] |
ط غيّر إعدادات حماية »وحدة:Webarchive«: بوت: [https://w.wiki/7NGP تحسين مستوي الحماية] ([تعديل=السماح للمحررين فقط] (غير محدد) [النقل=السماح للمحررين فقط] (غير محدد)) |
Mr. Ibrahem (نقاش | مساهمات) تحديث وسم: مُسترجَع |
||
سطر 1: | سطر 1: | ||
--[[ ---------------------------------- |
--[[ ---------------------------------- |
||
Lua module implementing the {{webarchive}} template. |
|||
A merger of the functionality of three templates: {{wayback}}, {{webcite}} and {{cite archives}} |
|||
]] |
|||
local p = {} |
|||
--[[--------------------------< |
--[[--------------------------< D E P E N D E N C I E S >------------------------------------------------------ |
||
]] |
|||
require('strict'); |
|||
Critical error. Render output completely in red. Add to tracking category. |
|||
local getArgs = require ('Module:Arguments').getArgs; |
|||
]] |
|||
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >-------------------------------------- |
|||
local function inlineError(arg, msg) |
|||
]] |
|||
local categories = {}; -- category names |
|||
track["Category:Webarchive template errors"] = 1 |
|||
local config = {}; -- global configuration settings |
|||
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 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 >----------------------- |
|||
--[[--------------------------< tableLength >----------------------- |
|||
Render a text fragment in red, such as a warning as part of the final output. |
|||
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["Category:Webarchive template warnings"] = 1 |
|||
elseif trackmsg == "error" then |
|||
track["Category:Webarchive template errors"] = 1 |
|||
end |
|||
local function make_wikilink (link, display, no_link) |
|||
return '<span style="font-size:100%" class="error citation-comment">' .. msg .. '</span>' |
|||
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 >----------------------- |
|||
--[[--------------------------< createTracking >----------------------- |
|||
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= |
|||
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 |
|||
--[[--------------------------< inlineError >----------------------- |
|||
return nil |
|||
else |
|||
Critical error. Render output completely in red. Add to tracking category. |
|||
return mw.text.trim(arg) |
|||
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 |
|||
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 |
|||
if value:match ('%W') then -- value must only be in the set [0-9a-zA-Z] |
|||
local r = 1 |
|||
return; -- nil return when value contains extraneous characters |
|||
end |
|||
local n = #value -- number of characters in value |
|||
if value:match( "^%w+$" ) then |
|||
local k = 1 |
|||
local c |
|||
r = 0 |
|||
local c |
|||
for i = n, 1, -1 do -- loop through all characters in value from ls digit to ms digit |
|||
r = 0 |
|||
c = value:byte( i, i ) |
|||
if c >= 48 and c <= 57 then -- character is digit 0-9 |
|||
c = value:byte( i, i ) |
|||
c = c - 48 |
|||
if c >= 48 and c <= 57 then |
|||
elseif c >= 65 and c <= 90 then -- character is ascii a-z |
|||
c = c - 48 |
|||
c = c - 55 |
|||
elseif c >= 65 and c <= 90 then |
|||
else -- must be ascii A-Z |
|||
c = c - 55 |
|||
c = c - 61 |
|||
elseif c >= 97 and c <= 122 then |
|||
end |
|||
c = c - 61 |
|||
r = r + c * k -- accumulate this base62 character's value |
|||
else -- How comes? |
|||
k = k * 62 -- bump for next |
|||
r = 1 |
|||
end -- for i |
|||
end |
|||
return r |
|||
r = r + c * k |
|||
k = k * 62 |
|||
end -- for i |
|||
end |
|||
return r |
|||
end |
end |
||
--[[--------------------------< tableLength >----------------------- |
|||
--[[--------------------------< D E C O D E _ D A T E >-------------------------------------------------------- |
|||
Given a 1-D table, return number of elements |
|||
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 |
|||
local function decode_date (date_str) |
|||
for _ in pairs(T) do count = count + 1 end |
|||
local patterns = { |
|||
return count |
|||
['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 >----------------------- |
|||
Given year, month, day numbers, (zero-padded or not) return a full date in df format |
|||
--[[--------------------------< dateFormat >----------------------- |
|||
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 |
|||
Given a date string, return its format: dmy, mdy, iso, ymd |
|||
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 function makeDate (year, month, day, df) |
|||
local dt = {} |
|||
local format = { |
|||
['dmy'] = 'j F Y', |
|||
['mdy'] = 'F j, Y', |
|||
['ymd'] = 'Y F j', |
|||
['iso'] = 'Y-m-d', |
|||
}; |
|||
local date = table.concat ({year, month, day}, '-'); -- assemble year-initial numeric-format date (zero padding not required here) |
|||
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 |
|||
if non_western_digits then -- this wiki uses non-western digits? |
|||
dt.split = mw.text.split(date, " ") |
|||
date = mw.ustring.gsub (date, '%d', digits); -- convert this wiki's non-western digits to western digits |
|||
if tableLength(dt.split) == 3 then |
|||
end |
|||
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 |
|||
return mw.getContentLanguage():formatDate (format[df], date); |
|||
end |
end |
||
--[[--------------------------< makeDate >----------------------- |
|||
--[[--------------------------< I S _ V A L I D _ D A T E >---------------------------------------------------- |
|||
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 |
|||
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 |
|||
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 function is_valid_date (year, month, day) |
|||
local zmonth = month -- month with leading 0 |
|||
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; |
|||
month = month:match("0*(%d+)") -- month without leading 0 |
|||
local month_length; |
|||
if tonumber(month) < 1 or tonumber(month) > 12 then |
|||
local y, m, d; |
|||
return year |
|||
local today = os.date ('*t'); -- fetch a table of current date parts |
|||
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 |
|||
if not year or '' == year or not month or '' == month or not day or '' == day then |
|||
local zday = day |
|||
return false; -- something missing |
|||
day = zday:match("0*(%d+)") |
|||
end |
|||
if tonumber(day) < 1 or tonumber(day) > 31 then |
|||
if df == "mdy" or df == "dmy" then |
|||
y = tonumber (year); |
|||
return nmonth .. " " .. year |
|||
m = tonumber (month); |
|||
elseif df == "iso" then |
|||
d = tonumber (day); |
|||
return year .. "-" .. zmonth |
|||
elseif df == "ymd" then |
|||
return year .. " " .. nmonth |
|||
else |
|||
return nmonth .. " " .. year |
|||
end |
|||
end |
|||
if 1900 > y or today.year < y or 1 > m or 12 < m then -- year and month are within bounds TODO: 1900? |
|||
if df == "mdy" then |
|||
return false; |
|||
return nmonth .. " " .. day .. ", " .. year -- September 1, 2016 |
|||
end |
|||
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 |
|||
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 |
||
سطر 208: | سطر 323: | ||
--[[--------------------------< decodeWebciteDate >----------------------- |
--[[--------------------------< 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' |
|||
]] |
|||
]] |
|||
local function decodeWebciteDate(path, df) |
local function decodeWebciteDate(path, df) |
||
local dt = {}; |
|||
local decode; |
|||
dt.split = {} |
|||
dt = 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 |
|||
-- http://www.webcitation.org/query?id=1138911916587475 |
|||
dt.full = os.date("%Y %m %d", string.sub(string.format("%d", base62(dt.split[2])),1,10) ) |
|||
-- http://www.webcitation.org/query?url=http..&date=2012-06-01+21:40:03 |
|||
dt.split = mw.text.split(dt.full, " ") |
|||
-- http://www.webcitation.org/1138911916587475 |
|||
dt.year = dt.split[1] |
|||
-- http://www.webcitation.org/cache/73e53dd1f16cf8c5da298418d2a6e452870cf50e |
|||
dt.month = dt.split[2] |
|||
-- http://www.webcitation.org/getfile.php?fileid=1c46e791d68e89e12d0c2532cc3cf629b8bc8c8e |
|||
dt.day = dt.split[3] |
|||
if dt[2]:find ('query', 1, true) or |
|||
if not tonumber(dt.year) or not tonumber(dt.month) or not tonumber(dt.day) then |
|||
dt[2]:find ('cache', 1, true) or |
|||
return inlineRed("[Date error] (1)", "error") |
|||
dt[2]:find ('getfile', 1, true) or |
|||
end |
|||
tonumber(dt[2]) then |
|||
return 'query'; |
|||
end |
|||
decode = base62(dt[2]); -- base62 string -> exponential number |
|||
if tonumber(dt.month) > 12 or tonumber(dt.day) > 31 or tonumber(dt.month) < 1 then |
|||
if not decode then |
|||
return inlineRed("[Date error] (2)", "error") |
|||
return nil; -- nil return when dt[2] contains characters not in %w |
|||
end |
|||
end |
|||
if tonumber(dt.year) > tonumber(os.date("%Y")) or tonumber(dt.year) < 1900 then |
|||
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 |
|||
return inlineRed("[Date error] (3)", "error") |
|||
end |
|||
decode = makeDate (dt.year, dt.month, dt.day, 'iso'); -- date comparisons are all done in iso format with western digits |
|||
if non_western_digits then -- this wiki uses non-western digits? |
|||
if not fulldate then |
|||
decode = mw.ustring.gsub (decode, '%d', digits); -- convert this wiki's non-western digits to western digits |
|||
return inlineRed("[Date error] (4)", "error") |
|||
end |
|||
else |
|||
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 ) |
||
or Library of Congress Web Archives (eg. /all/20160901010101/http://example.com) |
|||
return the formatted date eg. "September 1, 2016" in df format |
|||
or UK Government Web Archive (eg. /ukgwa/20160901010101/http://example.com or /tna/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 msg, snapdate; |
|||
local snapdate, snapdatelong, currdate, fulldate |
|||
snapdate = path:gsub ('^/web/', ''):gsub ('^/all/', ''):gsub ('^/ukgwa/', ''):gsub ('^/tna/', ''):gsub ('^/', ''); -- remove leading /web/, /all/, /ukgwa/, /tna/, or / |
|||
local safe = path |
|||
snapdate = snapdate:match ('^[^/]+'); -- get timestamp |
|||
snapdate = string.gsub(safe, "^/w?e?b?/?", "") -- Remove leading "/web/" or "/" |
|||
if snapdate == "*" then -- eg. /web/*/http.., etc. |
|||
safe = snapdate |
|||
return 'index'; -- return indicator that this url has an index date |
|||
local N = mw.text.split(safe, "/") |
|||
end |
|||
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 "*" |
|||
snapdate = snapdate:gsub ('%a%a_%d?$', ''):gsub ('%-', ''); -- from date, remove any trailing "re_", dashes |
|||
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 |
|||
msg = ''; |
|||
fulldate = makeDate(year, month, day, df) |
|||
if snapdate:match ('%*$') then -- a trailing '*' causes calendar display at archive .org |
|||
if not fulldate then |
|||
snapdate = snapdate:gsub ('%*$', ''); -- remove so not part of length calc later |
|||
return inlineRed("[Date error] (7)", "error") |
|||
msg = inlineRed (err_warn_msgs.ts_cal, 'warning'); -- make a message |
|||
else |
|||
end |
|||
return fulldate |
|||
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 |
||
--[[--------------------------< |
--[[--------------------------< decodeArchiveisDate >----------------------- |
||
Given an Archive.is "long link" URI-path (e.g. /2016.08.28-144552/http://example.com) |
|||
Given a domain extracted by mw.uri.new() (eg. web.archive.org) set tail string and service ID |
|||
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 function decodeArchiveisDate(path, df) |
|||
local tracking = "Category:Webarchive template other archives" |
|||
local snapdate |
|||
if path:match ('^/%w+$') then -- short form url path is '/' followed by some number of base 62 digits and nothing else |
|||
local bracketopen = "[[" |
|||
return "short link" -- e.g. http://archive.is/hD1qz |
|||
local bracketclose = "]]" |
|||
end |
|||
if nolink then |
|||
bracketopen = "" |
|||
bracketclose = "" |
|||
end |
|||
snapdate = mw.text.split (path, '/')[2]:gsub('[%.%-]', ''); -- get snapshot date, e.g. 2016.08.28-144552; remove periods and hyphens |
|||
ulx.url1.service = "other" |
|||
ulx.url1.tail = " at " .. ulx.url1.host |
|||
local dlen = string.len(snapdate) |
|||
if mw.ustring.find( host, "archive.org", 1, plain ) then |
|||
if dlen < 8 then -- we need 8 digits TODO: but shouldn't this be testing for 14 digits? |
|||
ulx.url1.service = "wayback" |
|||
return '', inlineRed (err_warn_msgs.ts_short, 'error'); -- return empty string and error message |
|||
ulx.url1.tail = " على موقع " .. bracketopen .. "واي باك مشين" .. bracketclose |
|||
end |
|||
tracking = "تصنيف:قالب أرشيف الإنترنت بوصلات واي باك"--"Category:Webarchive template wayback links" |
|||
elseif mw.ustring.find( host, "webcitation.org", 1, plain ) then |
|||
ulx.url1.service = "webcite" |
|||
ulx.url1.tail = " at " .. bracketopen .. "WebCite" .. bracketclose |
|||
tracking = "Category:Webarchive template webcite links" |
|||
elseif mw.ustring.find( host, "archive.is", 1, plain ) then |
|||
ulx.url1.service = "archiveis" |
|||
ulx.url1.tail = " at " .. bracketopen .. "Archive.is" .. bracketclose |
|||
tracking = "Category: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 = "Category:Webarchive template archiveis links" |
|||
elseif mw.ustring.find( host, "archive-it", 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 " .. "Portugese 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 = " على موقع " .. "[[مكتبة الإسكندرية الجديدة]]" |
|||
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, "nlib.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 = " على موقع " .. "Web Archive Singapore" |
|||
elseif mw.ustring.find( host, "nlb.gov.sg", 1, plain ) then |
|||
ulx.url1.tail = " على موقع " .. "Web Archive Singapore" |
|||
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 = " على موقع " .. "Wikiwix" |
|||
elseif mw.ustring.find( host, "perma.cc", 1, plain ) then |
|||
ulx.url1.tail = " على موقع " .. bracketopen .. "Perma.cc" .. bracketclose |
|||
else |
|||
tracking = "Category:Webarchive template unknown archives" |
|||
end |
|||
local year, month, day = snapdate:match ('(%d%d%d%d)(%d%d)(%d%d)'); -- no need for snapdatelong here |
|||
track[tracking] = 1 |
|||
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 |
|||
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(args) |
||
local i, j, argurl, argurl2, argdate, argtitle |
|||
j = 2 |
|||
for i = 2, config.maxurls do |
|||
argurl = "url" .. i |
|||
if args[argurl] then |
|||
argurl2 = "url" .. j |
|||
ulx[argurl2] = {} |
|||
ulx[argurl2]["url"] = args[argurl] |
|||
argdate = "date" .. i |
|||
if args[argdate] then |
|||
ulx[argurl2]["date"] = args[argdate] |
|||
else |
|||
ulx[argurl2]["date"] = inlineRed (err_warn_msgs.date_miss, 'warning'); |
|||
end |
|||
argtitle = "title" .. j |
|||
argtitle = "title" .. i |
|||
if trimArg(args[argtitle]) then |
|||
if args[argtitle] then |
|||
ulx[argurl2]["title"] = args[argtitle] |
|||
else |
|||
else |
|||
ulx[argurl2]["title"] = nil |
|||
ulx[argurl2]["title"] = nil |
|||
end |
|||
end |
|||
j = j + 1 |
|||
j = j + 1 |
|||
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 |
|||
]] |
|||
local function comma(date) |
local function comma(date) |
||
return (date and date:match ('%a+ +%d%d?(,) +%d%d%d%d')) or ''; |
|||
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 |
end |
||
--[[--------------------------< createTracking >----------------------- |
|||
--[[--------------------------< createRendering >----------------------- |
|||
Return data in track[] ie. tracking categories |
|||
Return a rendering of the data in ulx[][] |
|||
]] |
|||
]] |
|||
local function createTracking() |
|||
local function createRendering() |
|||
if tableLength(track) > 0 then |
|||
for key,_ in pairs(track) do |
|||
sand = sand .. "[[" .. key .. "]]" |
|||
end |
|||
end |
|||
return sand |
|||
local displayfield |
|||
local out = {}; |
|||
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 '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 |
|||
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, '.') -- 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 >----------------------- |
|||
--[[--------------------------< P A R A M E T E R _ N A M E _ X L A T E >-------------------------------------- |
|||
Return a rendering of the data in ulx[][] |
|||
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? |
|||
local function createRendering() |
|||
returns two tables: |
|||
local sand, displayheader, displayfield |
|||
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 |
|||
local period1 = "" -- For backwards compat with {{Wayback}} |
|||
local period2 = "." |
|||
local indexstr = "نسخة محفوظة" |
|||
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 .. " نسخة محفوظة]" .. 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 .. " نسخة محفوظة] " .. 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}} |
|||
local function parameter_name_xlate (args, params, enum_params) |
|||
else |
|||
local name; -- holds modifiable name of the parameter name during evaluation |
|||
if ulx.url1.format == "addlarchives" then -- Multiple archive services |
|||
local enum; -- for enumerated parameters, holds the enumerator during evaluation |
|||
displayheader = "Additional archives: " |
|||
local found = false; -- flag used to break out of nested for loops |
|||
else -- Multiple pages from the same archive |
|||
local new_args = {}; -- a table that holds canonical and translated parameter k/v pairs |
|||
displayheader = "المزيد من النسخ المحفوظة on " .. ulx.url1.date .. ": " |
|||
local origin = {}; -- a table that maps original (local language) parameter names to their canonical name for local language error messaging |
|||
end |
|||
local unnamed_params; -- set true when unsupported positional parameters are detected |
|||
local tot = 1 + ulx.url1.extraurls |
|||
local sand = displayheader |
|||
for k, v in pairs (args) do -- loop through all of the arguments in the args table |
|||
for i=1,tot do |
|||
name = k; -- copy of original parameter name |
|||
local indx = "url" .. i |
|||
displayfield = ulx[indx]["title"] |
|||
if 'string' == type (k) then |
|||
if non_western_digits then -- true when non-western digits supported at this wiki |
|||
if not displayfield then |
|||
name = mw.ustring.gsub (name, '%d', digits); -- convert this wiki's non-western digits to western digits |
|||
displayfield = ulx[indx]["date"] |
|||
end |
|||
else |
|||
enum = name:match ('%d+$'); -- get parameter enumerator if it exists; nil else |
|||
if not displayfield then |
|||
displayfield = "Page " .. i |
|||
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 |
|||
end |
|||
for pname, aliases in pairs (params) do -- loop through each parameter the params table |
|||
sand = sand .. "[" .. ulx[indx]["url"] .. " " .. displayfield .. "]" |
|||
for _, alias in ipairs (aliases) do -- loop through each alias in the parameter's aliases table |
|||
if i == tot then |
|||
if name == alias then |
|||
sand = sand .. "." |
|||
new_args[pname] = v; -- create a new entry in the new_args table |
|||
else |
|||
origin [pname] = k; -- create an entry to make canonical parameter name to original local language parameter name |
|||
sand = sand .. ", " |
|||
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 |
|||
end |
|||
end |
|||
return sand |
|||
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. |
|||
--[[--------------------------< W E B A R C H I V E >---------------------------------------------------------- |
|||
-- URL argument (first) |
|||
template entry point |
|||
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 |
|||
]] |
|||
ulx.url1 = {} |
|||
ulx.url1.url = url1 |
|||
local uri1 = mw.uri.new(ulx.url1.url) |
|||
ulx.url1.host = uri1.host |
|||
ulx.url1.extraurls = parseExtraArgs() |
|||
local function webarchive(frame) |
|||
-- Nolink argument |
|||
local args = getArgs (frame); |
|||
local data = mw.loadData (table.concat ({ -- make a data module name; sandbox or live |
|||
local nolink = trimArg2(args.nolink) |
|||
'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; |
|||
local origin = {}; -- holds a map of English to local language parameter names used in the current template; not currently used |
|||
serviceName(uri1.host, nolink) |
|||
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 |
|||
local date, format, msg, udate, uri, url; |
|||
-- Date argument |
|||
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 |
|||
]] |
|||
if not (url:lower():find ('^http') or url:find ('^//')) then |
|||
local date = trimArg(args.date) or trimArg(args.date1) |
|||
return inlineError (data.crit_err_msgs.invalid_url ); |
|||
if date == "*" and ulx.url1.service == "wayback" then |
|||
end |
|||
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 = date -- .. 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 |
|||
ulx.url1 = {} |
|||
-- Format argument |
|||
ulx.url1.url = url |
|||
ulx.url1.extraurls = parseExtraArgs(args) |
|||
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 |
|||
local good = false; |
|||
-- Title argument |
|||
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) |
|||
if args.date and args.date1 then -- Date argument |
|||
local title = trimArg(args.title) or trimArg(args.title1) |
|||
return inlineError (data.crit_err_msgs.conflicting, {origin.date, origin.date1}); |
|||
ulx.url1.title = title |
|||
end |
|||
date = args.date or args.date1; |
|||
date = date and date:gsub (' +', ' '); -- replace multiple spaces with a single space |
|||
if date and config.verifydates then |
|||
local rend = createRendering() |
|||
if '*' == date then |
|||
date = 'index'; |
|||
rend = '<span style="font-size:100%" class="error citation-comment">Error in [[:Template:' .. tname .. ']]: Unknown problem. Please report on template talk page.</span>' |
|||
ldf = 'iso'; -- set to default format |
|||
track["Category:Webarchive template errors"] = 1 |
|||
elseif 'mdy' == date then |
|||
end |
|||
date = nil; -- if date extracted from URL, |
|||
ldf = 'mdy'; -- then |date=mdy overrides iso |
|||
elseif 'dmy' == date then |
|||
date = nil; -- if date extracted from URL, |
|||
ldf = 'dmy'; -- then |date=dmy overrides iso |
|||
elseif 'ymd' == date then |
|||
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.service or 'locwebarchives' == ulx.url1.service or 'ukgwa' == ulx.url1.service then |
|||
return rend .. createTracking() |
|||
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}; |
نسخة 20:52، 3 يونيو 2024
![]() | هذه الوحدة مستخدمة في عدد كبير من الصفحات (+346646) . لتفادي خلق بلبلة على نطاق واسع من الصفحات وزيادة الأعباء على الخوادم، يجب تجربة أي تعديل في هذه الصفحات الفرعية /ملعب أو /تجربة أو في ملعبك. بعدها يمكنك اضافة التعديلات دفعة واحدة، ورجاءً، لا تنسَ مناقشة أمر التعديلات أوّلًا قبل القيام بها. |
![]() | هذا القالب مخصص للوصلات الخارجية، وليس لاستخدامه في قوالب الاستشهاد بالمراجع. |
![]() | هذه الوحدة تعتمد على الوحدات الأخرى التالية: |
يستخدم قالب {{Webarchive}} لربط خدمات أرشفة الويب مثل واي باك مشين وويب سايت.
الاستخدام
Note: The most common method for linking a web archive are the CS1|2 templates such as {{cite web}}
with the |archive-url=
, |archive-date=
, and |url-status=
parameters. Please be aware of ويكيبيديا:الاستشهاد بمصادر before converting this template to a CS1|2 template.
Usage
In most cases the template needs only two parameters, the archive |url=
and archive |date=
. It is also common to include a |title=
. For some URLs, the template can automatically display the date. To prevent the template from adding a wikilink to the name of the أرشفة الويب site, use the |nolink=
parameter with any value.
- Usage with
|url=
and|date=
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |date=2 August 2016}}
- نسخة محفوظة 2 أغسطس 2016 في Wayback Machine
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com/ |date=12 February 2009}}
- نسخة محفوظة 12 فبراير 2009 في WebCite
- Usage with
|url=
and|title=
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |title=Page title}}
- Page title في Wayback Machine (نسخة محفوظة 2016-08-02)
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com/ |title=Page title}}
- Page title في WebCite (نسخة محفوظة 2009-02-12)
- Usage with
|url=
,|date=
and|title=
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |date=August 2, 2016 |title=Page title}}
- Page title في Wayback Machine (نسخة محفوظة أغسطس 2, 2016)
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com/ |date=February 12, 2009 |title=Page title}}
- Page title في WebCite (نسخة محفوظة فبراير 12, 2009)
- Usage with
|url=
,|date=
and|nolink=
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |date=August 2, 2016 |nolink=y}}
- نسخة محفوظة أغسطس 2, 2016 في Wayback Machine
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com/ |date=February 12, 2009 |nolink=1}}
- نسخة محفوظة فبراير 12, 2009 في WebCite
Multiple URLs
The template optionally supports multiple URLs (up to 10) for linking to multiple archiving services for the same source link. The first url argument is |url=
then |url2=
.. |url10=
. Each URL can have its own date and title argument, thus |date2=
.. |date10=
and |title2=
.. |title10=
.
خيارات
Main parameters
- url..url10
- The URL(s) to the archive service. There should always be a
|url=
which counts as the first url. Each|url#=
can have its own numbered corresponding|date#=
and|title#=
. Matching of URL with date and title is done by numbers, not position. Numbers do not need to be in sequence, for example|url2=
followed by|url5=
works. - date..date10
- The date the page was archived. The date format displayed is the same as entered. If
|date=
is missing the template will make a best effort to find the date by decoding the archive URL (wayback and webcite for example provide this data in the URL), and will display the date in iso format by default. However including a date is recommended for date formatting reasons, and because other tools may not have the ability to decode the date from the URL. - title..title10
- The text displayed for the link. If no
|title=
is provided then|date=
is displayed. Otherwise|title=
takes precedence if both are set.
Secondary parameters
- nolink
- If set to any value, the archive service name will not be wikilinked.
- format
- This is a special option to support the merger of
{{cite archives}}
. It may be deprecated in the future. Because CS1|2 templates do not currently support more than one archive link, this template will tack on additional archive links to the end of a CS1|2 template output. It takes two values:|format=addlarchives
or|format=addlpages
. Addlarchives will display output appropriate for linking to multiple web archiving services. Addlpages will display output appropriate for linking to multiple pages at the same archive.
أمثلة
The number of possible examples is extensive depending on the mix of options. Some common cases follow. For more extensive testing see the testcases page [الإنجليزية].
- Single link at واي باك مشين with date and title (recommended method)
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |date=August 2, 2016 |title=Page title}}
- Page title في Wayback Machine (نسخة محفوظة أغسطس 2, 2016)
- Single link at Wayback Machine with date only
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |date=August 1, 2016}}
- نسخة محفوظة أغسطس 2, 2016 في Wayback Machine
- Single link at Wayback Machine with title; date extracted from URL
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |title=Example}}
- Example في Wayback Machine (نسخة محفوظة 2016-08-02)
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |title=Example |date=mdy}}
- Example في Wayback Machine (نسخة محفوظة أغسطس 2, 2016)
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |title=Example |date=dmy}}
- Example في Wayback Machine (نسخة محفوظة 2 أغسطس 2016)
- Single link at ويب سايت with title; date extracted from URL
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com |title=Example}}
- Example في WebCite (نسخة محفوظة 2009-02-12)
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com |title=Example |date=mdy}}
- Example في WebCite (نسخة محفوظة فبراير 12, 2009)
{{Webarchive|url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com |title=Example |date=dmy}}
- Example في WebCite (نسخة محفوظة 12 فبراير 2009)
- Single link at أرشيف.تودي with title; date extracted from URL
{{Webarchive|url=https://archive.today/2016.08.08-112330/http://example.com |title=Example}}
- Example في archive.today (نسخة محفوظة 2016-08-08)
{{Webarchive|url=https://archive.today/2016.08.08-112330/http://example.com |title=Example |date=mdy}}
- Example في archive.today (نسخة محفوظة أغسطس 8, 2016)
{{Webarchive|url=https://archive.today/2016.08.08-112330/http://example.com |title=Example |date=dmy}}
- Example في archive.today (نسخة محفوظة 8 أغسطس 2016)
- Multi-link at Wayback Machine with dates and titles (recommended method)
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |title=Page title |date=August 2, 2016 |url2=https://web.archive.org/web/20160902000046/http://example.com/ |title2=Page2 title |date2=September 2, 2016}}
- Page title في Wayback Machine (نسخة محفوظة أغسطس 2, 2016). Additional archives: Page2 title.
- Multi-link at Wayback Machine with dates only
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |date=August 2, 2016 |url2=https://web.archive.org/web/20160902000046/http://example.com/ |date2=September 2, 2016}}
- نسخة محفوظة أغسطس 2, 2016 في Wayback Machine. Additional archives: September 2, 2016.
- Multi-link at Wayback Machine with titles only
{{Webarchive|url=https://web.archive.org/web/20160802001301/http://example.com/ |title=Page title |url2=https://web.archive.org/web/20160902000046/http://example.com/ |title2=Page2 title}}
- Page title في Wayback Machine (نسخة محفوظة 2016-08-02). Additional archives: Page2 title.
- Additional archives format
{{Webarchive|format=addlarchives |url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com/ |date=12 February 2009}}
- Additional archives: 12 فبراير 2009.
- Additional pages format
{{Webarchive|format=addlpages |url=https://www.webcitation.org/5eWaHRbn4?url=http://www.example.com/ |url2=https://web.archive.org/web/20160902000046/http://example.com/ |date=12 February 2009}}
- المزيد من النسخ المحفوظة في 12 فبراير 2009: Page 1, Page 2.
تصنيفات تتبع
يتم إضافتها عبر وحدة:Webarchive:
Tracking archive sites
- تصنيف:قالب أرشيف الإنترنت بوصلات واي باك (345٬943 صفحة) – وصلا الى واي باك مشين
- تصنيف:Webarchive template webcite links (58 صفحة) – وصلات إلى WebCite
- تصنيف:Webarchive template archiveis links (1٬901 صفحة) – وصلات إلى Archive.today
- تصنيف:Webarchive template other archives (146 صفحة) – وصلات الى مواقع أرشيف لا يوجد تصانيف تتبع خاصة بها
- تصنيف:Webarchive template unknown archives (249 صفحة) –القالب لا يتعرف على وصلة الأرشيف؛ هذا قد يشير إلى وجود خطأ في البيانات، أو أن القالب يحتاج إلى تحديث لمواكبة مواقع الأرشيفات الجديدة.
Tracking warnings and errors
- تصنيف:Webarchive template warnings (122 صفحة) – الأخطاء البسيطة التي لا تمنع القالب من العمل ولكنها تترك رسالة حمراء
- تصنيف:Webarchive template errors (62 صفحة) – الأخطاء التي تتطلب عادة تدخل بشري
صيانة القالب
يمكن القيام بالتالي لصيانة القالب.
مراقبة تصنيفات التتبع
يمكن مراقبة تصنيفات التتبع لـ "التحذيرات" و "الأخطاء" للإنذار بأي مشاكل في البيانات.
قد يشير تصنيف التتبع لـ "الأرشيفات المجهولة" إلى وجود مشكلة في البيانات. على سبيل المثال، قد يستخدم المحرر عنوان URL المصدر بدلاً من عنوان URL الأرشيف في حقل |url=
.
التكوين: التحقق من التواريخ (verifydates)
يمكن للقالب التحقق من تطابق تواريخ Wayback (أو WebCite) في جزء عنوان URL مع التاريخ في |date=
. إذا لم تتطابق التواريخ، فسيترك رسالة تحذيرية حمراء "عدم تطابق التاريخ" ويضيف المقالة إلى تصنيف التتبع للتحذيرات.
نظرًا لأن وظيفة التحقق تضيف بعض العبء إلى القالب، يمكن تعطيلها عالميًا اختياريًا عن طريق تعيين المتغير "verifydates = no" (انظر مصدر الوحدة في الوظيفة p.webarchive()). لاحظ أنه بعد التعيين على "نعم"، قد يستغرق الأمر أسبوعًا أو أكثر لاكتمال تصنيف التتبع. ضعه على "نعم" إذا كنت تبحث عن مشاكل في البيانات التي تحتاج إلى إصلاح (ستظهر في تصنيف التتبع).
التكوين: maxurls الحد الأقصى لعدد عناوين URL هو 10 ولكن يمكن تغيير ذلك عن طريق تعيين المتغير "maxurls" في وظيفة p.webarchive(). هذا متغير عالمي سيؤثر على جميع حالات القالب، استخدمه بحذر. ستزيد تقليل العدد من سرعة القالب وتقليل استخدام الموارد.
وسائط المحرر المرئي
بيانات قالب: «Webarchive»
قالب لربط الأرشيفات الخارجية مثل Wayback و WebCite و Archive.is وما إلى ذلك.
وسيط | وصف | نوع | حالة | |
---|---|---|---|---|
عنوان الأرشيف | url | عنوان URL للأرشيف.
| نص | مطلوب |
تاريخ الأرشيف | date | تاريخ الأرشيف.
| نص | مقترح |
عنوان الأرشيف | title | العنوان (أو النص) المعروض على صفحة الويكي للرابط.
| نص | مقترح |
وصلة الويكي | nolink | وصلة الويكي إلى صفحة الأرشيف في التقديم. أي قيمة بما في ذلك الفراغ يعني عدم وجود وصلة ويتم تجاهلها. | نص | اختياري |
تنسيق عرض القالب. | format | في حالة وجود عدة عناوين URL، يتم عرض العرض في إحدى صيغتين. | نص | اختياري |
--[[ ----------------------------------
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');
local getArgs = require ('Module:Arguments').getArgs;
--[[--------------------------< F O R W A R D D E C L A R A T I O N S >--------------------------------------
]]
local categories = {}; -- category names
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
--[[--------------------------< 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
--[=[-------------------------< 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.
]=]
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
--[[--------------------------< createTracking >-----------------------
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
end
--[[--------------------------< inlineError >-----------------------
Critical error. Render output completely in red. Add to tracking category.
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
--[[--------------------------< 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 >-----------------------
Convert base-62 to base-10
Credit: https://de.wikipedia.org/wiki/Modul:Expr
]]
local function base62( value )
local r = 1 -- default return value is input value is malformed
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
local n = #value -- number of characters in value
local k = 1
local c
r = 0
for i = n, 1, -1 do -- loop through all characters in value from ls digit to ms digit
c = value:byte( i, i )
if c >= 48 and c <= 57 then -- character is digit 0-9
c = c - 48
elseif c >= 65 and c <= 90 then -- 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
return r
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
]]
local function decode_date (date_str)
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
--[[--------------------------< 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
]]
local function makeDate (year, month, day, df)
local format = {
['dmy'] = 'j F Y',
['mdy'] = 'F j, Y',
['ymd'] = 'Y F j',
['iso'] = 'Y-m-d',
};
local date = table.concat ({year, month, day}, '-'); -- assemble year-initial numeric-format date (zero padding not required here)
if non_western_digits then -- this wiki uses non-western digits?
date = mw.ustring.gsub (date, '%d', digits); -- convert this wiki's non-western digits to western digits
end
return mw.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
]]
local function is_valid_date (year, month, day)
local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
local month_length;
local y, m, d;
local today = os.date ('*t'); -- fetch a table of current date parts
if not year or '' == year or not month or '' == month or not day or '' == day then
return false; -- something missing
end
y = tonumber (year);
m = tonumber (month);
d = tonumber (day);
if 1900 > y or today.year < y or 1 > m or 12 < m then -- year and month are within bounds TODO: 1900?
return false;
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
--[[--------------------------< 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'
]]
local function decodeWebciteDate(path, df)
local dt = {};
local decode;
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
if dt[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
if not decode then
return nil; -- 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
if non_western_digits then -- this wiki uses non-western digits?
decode = mw.ustring.gsub (decode, '%d', digits); -- convert this wiki's non-western digits to western digits
end
return decode;
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
]]
local function decodeWaybackDate(path, df)
local msg, snapdate;
snapdate = path:gsub ('^/web/', ''):gsub ('^/all/', ''):gsub ('^/ukgwa/', ''):gsub ('^/tna/', ''):gsub ('^/', ''); -- remove leading /web/, /all/, /ukgwa/, /tna/, or /
snapdate = snapdate:match ('^[^/]+'); -- get timestamp
if snapdate == "*" 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 = '';
if snapdate: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
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
--[[--------------------------< 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
]]
local function decodeArchiveisDate(path, df)
local snapdate
if path: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
local dlen = string.len(snapdate)
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; -- 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
--[[--------------------------< 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(args)
local i, j, argurl, argurl2, argdate, argtitle
j = 2
for i = 2, config.maxurls do
argurl = "url" .. i
if args[argurl] then
argurl2 = "url" .. j
ulx[argurl2] = {}
ulx[argurl2]["url"] = args[argurl]
argdate = "date" .. i
if args[argdate] then
ulx[argurl2]["date"] = args[argdate]
else
ulx[argurl2]["date"] = inlineRed (err_warn_msgs.date_miss, 'warning');
end
argtitle = "title" .. i
if 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)
return (date and date:match ('%a+ +%d%d?(,) +%d%d%d%d')) or '';
end
--[[--------------------------< createRendering >-----------------------
Return a rendering of the data in ulx[][]
]]
local function createRendering()
local displayfield
local out = {};
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 '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
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, '.') -- 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
--[[--------------------------< 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
]]
local function parameter_name_xlate (args, params, enum_params)
local name; -- holds modifiable name of the parameter name during evaluation
local enum; -- for enumerated parameters, holds the enumerator during evaluation
local found = false; -- flag used to break out of nested for loops
local new_args = {}; -- a table that holds canonical and translated parameter k/v pairs
local origin = {}; -- a table that maps original (local language) parameter names to their canonical name for local language error messaging
local unnamed_params; -- set true when unsupported positional parameters are detected
for k, v in pairs (args) do -- loop through all of the arguments in the args table
name = k; -- copy of original parameter name
if 'string' == type (k) then
if non_western_digits then -- 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
if not enum then -- 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
for pname, aliases in pairs (params) do -- loop through each parameter the params table
for _, alias in ipairs (aliases) do -- loop through each alias in the parameter's aliases table
if name == alias then
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
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
--[[--------------------------< W E B A R C H I V E >----------------------------------------------------------
template entry point
]]
local function webarchive(frame)
local args = getArgs (frame);
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;
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
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
]]
if not (url:lower():find ('^http') or url:find ('^//')) then
return inlineError (data.crit_err_msgs.invalid_url );
end
ulx.url1 = {}
ulx.url1.url = url
ulx.url1.extraurls = parseExtraArgs(args)
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)
if args.date and args.date1 then -- Date argument
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
if date and config.verifydates then
if '*' == date then
date = 'index';
ldf = 'iso'; -- set to default format
elseif 'mdy' == date then
date = nil; -- if date extracted from URL,
ldf = 'mdy'; -- then |date=mdy overrides iso
elseif 'dmy' == date then
date = nil; -- if date extracted from URL,
ldf = 'dmy'; -- then |date=dmy overrides iso
elseif 'ymd' == date then
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.service or 'locwebarchives' == ulx.url1.service or 'ukgwa' == 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
--[[--------------------------< E X P O R T E D F U N C T I O N S >------------------------------------------
]]
return {webarchive = webarchive};