Moduł:Sprawdź: Różnice pomiędzy wersjami
Przejdź do nawigacji
Przejdź do wyszukiwania
m 1 wersja |
pl>Paweł Ziemian drobne techniczne |
||
Linia 1: | Linia 1: | ||
local function checkUri(uri) | |||
local urilen = #uri | |||
for _,v in ipairs(mw.loadData("Moduł:Cytuj/dane").supportedUriSchemas) do | |||
if (#v < urilen) and (string.lower(string.sub(uri,1, #v)) == v) then | |||
return not string.match(uri, '%s') | |||
end | |||
end | |||
end | |||
function checkImageName(name) | |||
if not name or (#name==0) or string.match(name, "[#<>%[%]|{}]") then | |||
return false | |||
end | |||
local title = mw.title.makeTitle("Plik", name) | |||
if not title then | |||
return false | |||
end | |||
local res = { | |||
prefix = { | |||
plik = true, | |||
image = true, | |||
grafika = true, | |||
file = true, | |||
}, | |||
extension = { | |||
jpg = true, | |||
jpeg = true, | |||
jpe = true, | |||
png = true, | |||
svg = true, | |||
tif = true, | |||
tiff = true, | |||
gif = true, | |||
xcf = true, | |||
pdf = true, | |||
djvu = true, | |||
webp = true, | |||
}, | |||
} | |||
local prefix = string.match(name, "^:? *([^:]+) *:") | |||
if prefix and res.prefix[string.lower(prefix)] then | |||
return false | |||
end | |||
local extension = string.match(name, "%S.*%.([^%.]+)$") | |||
return extension and res.extension[string.lower(extension)] | |||
end | |||
local function findPlainHttp(text) | |||
if text then | |||
text = mw.ustring.gsub(text, "%[[hH][tT][tT][pP][sS]?://%S+", "_") | |||
return string.match(text, "[hH][tT][tT][pP][sS]?://%S") | |||
end | |||
end | |||
local function findFile(text) | |||
-- schowaj wyjątek: obrazek generowany przez Szablon:Link-interwiki | |||
text = mw.ustring.gsub(text, "%[%[Plik:Wikidata%-logo%-en%.svg|10x9px|link=:d:Q%d+|Informacje powiązane z artykułem „.-” w Wikidanych%]%]", "") | |||
-- normalize | |||
text = mw.ustring.gsub(text, "%s*[Pp]lik%s*:%s*", "Plik:") | |||
text = mw.ustring.gsub(text, "%s*[Ff]ile%s*:%s*", "Plik:") | |||
text = mw.ustring.gsub(text, "%s*[Gg]rafika%s*:%s*", "Plik:") | |||
text = mw.ustring.gsub(text, "%s*[Ii]mage%s*:%s*", "Plik:") | |||
return mw.ustring.match(text, "%[%[Plik:([^%[%]|]+)[|%]]") | |||
end | |||
-- Lista of template params for wikicode. Like this: | |||
-- | grafika = | data śmierci = | www = | |||
local function listToTplParams(strArray) | |||
return "| " .. table.concat(strArray, " = | ") .. " ="; | |||
end | |||
local function showTemplate(templateName, args) | |||
local result = {} | |||
local flags = {} | |||
table.insert(result, mw.text.nowiki("{{")) | |||
if mw.isSubsting() then | |||
table.insert(result, "subst:") | |||
end | |||
local title = mw.title.new(templateName) | |||
if title.namespace ~= 10 then | |||
table.insert(result, title.nsText) | |||
table.insert(result, ":") | |||
end | |||
table.insert(result, title.text) | |||
if args then | |||
local i = 1 | |||
while args[i] do | |||
table.insert(result, "|") | |||
table.insert(result, mw.text.nowiki(args[i])) | |||
i = i + 1 | |||
end | |||
for k, v in pairs(args) do | |||
local index = tonumber(k) | |||
if (type(k) == "string") or (index and ((index < 1) or (index > i))) then | |||
table.insert(result, "|") | |||
table.insert(result, tostring(k)) | |||
table.insert(result, "=") | |||
table.insert(result, mw.text.nowiki(v)) | |||
end | |||
end | |||
end | |||
table.insert(result, mw.text.nowiki("}}")) | |||
return table.concat(result) | |||
end | |||
local function infoboxCatTitle(infobox, class) | |||
local catTitle = mw.title.makeTitle(14, "Infoboksy – "..class.." – "..infobox) | |||
if not catTitle.exists then | |||
mw.logObject(catTitle, "Dedykowana kategoria błędów w infoboksie nie istnieje") | |||
catTitle = mw.title.makeTitle(14, "Infoboksy – "..class) | |||
end | |||
mw.logObject(catTitle, "infoboxCatTitle") | |||
return catTitle | |||
end | |||
local function daysInMonth(year, month) | |||
if month == 1 then return 31 end | |||
if month == 2 then return ((year % 4) == 0) and 29 or 28 end | |||
if month == 3 then return 31 end | |||
if month == 4 then return 30 end | |||
if month == 5 then return 31 end | |||
if month == 6 then return 30 end | |||
if month == 7 then return 31 end | |||
if month == 8 then return 31 end | |||
if month == 9 then return 30 end | |||
if month == 10 then return 31 end | |||
if month == 11 then return 30 end | |||
if month == 12 then return 31 end | |||
return 0 | |||
end | |||
local function isDate20YYMMDD(date) | |||
local y, m, d = mw.ustring.match(date, "^(20[0-9][0-9])%-([01][0-9])%-([0123][0-9])$") | |||
local year = tonumber(y) | |||
local month = tonumber(m) | |||
local day = tonumber(d) | |||
local result = year and month and day | |||
and (year >= 2001) | |||
and (month >= 1) and (month <= 12) | |||
and (day >= 1) and (day <= daysInMonth(year, month)) | |||
if not result then | |||
mw.logObject({date=date,year=year,month=month,day=day}, "isDate20YYMMDD") | |||
end | |||
return result | |||
end | |||
return { | return { | ||
["Porównaj"] = function(frame) | ["Porównaj"] = function(frame) | ||
Linia 139: | Linia 295: | ||
["Parametry"] = function(frame) | ["Parametry"] = function(frame) | ||
if mw.title.getCurrentTitle().contentModel ~= "wikitext" then | |||
mw.logObject(mw.title.getCurrentTitle().contentModel, "mw.title.getCurrentTitle().contentModel") | |||
return -- to nie ma sensu w takim wypadku | |||
end | |||
local unknown = {} | local unknown = {} | ||
local invalid = {} | local invalid = {} | ||
local deprecated = {} | local deprecated = {} | ||
local nakedurl = {} | |||
local files = {} | |||
local templateName = frame:getParent():getTitle() | |||
local infobox = mw.ustring.match(templateName, "^Szablon:(.- infobox)$") | |||
local config = frame.args[""] | local config = frame.args[""] | ||
local class, category = string.match( | local class, space, category = string.match(config or "", "^%s*(%S+)(%s+)(.-)%s*$") | ||
local nl = space and string.match(space, "\n") or "" | |||
class = class or config | |||
local function argName(arg) | local function argName(arg) | ||
return type(arg) ~= "string" and tostring(arg) or ('"'..arg..'"') | return type(arg) ~= "string" and tostring(arg) or ('"'..arg..'"') | ||
end | end | ||
local required = {} | |||
for k, v in pairs(frame.args) do | |||
if mw.ustring.match(v, "!$") then | |||
required[k] = true | |||
if infobox then | |||
-- odróżniaj pola sugerowane w infoboksach, które mogą być puste | |||
if v == "!" or mw.ustring.match(v, "%?!$") then | |||
required[k] = false | |||
else | |||
local pattern = string.match(v,"^(^.-$)!?$") | |||
if pattern and mw.ustring.match("", pattern) then | |||
required[k] = false | |||
end | |||
end | |||
end | |||
end | |||
end | |||
local emptyArg = false | local emptyArg = false | ||
for k, v in pairs(frame:getParent().args) do | for k, v in pairs(frame:getParent().args) do | ||
required[k] = nil | |||
local kind = frame.args[k] | local kind = frame.args[k] | ||
if kind == "" or kind == "!" then | |||
kind = "text?" | |||
end | |||
if k == "" then | if k == "" then | ||
emptyArg = v | emptyArg = v | ||
elseif not kind then | elseif not kind then | ||
table.insert(unknown, argName(k)) | table.insert(unknown, argName(k)) | ||
elseif kind == "num" then | elseif (kind == "num") or (kind == "num!") then | ||
local n = tonumber(v) | local n = tonumber(v) | ||
if not n then table.insert(invalid, argName(k)) end | if not n then table.insert(invalid, argName(k)) end | ||
elseif kind == "num?" then | elseif (kind == "num?") or (kind == "num?!") then | ||
local n = (#v == 0) or tonumber(v) | local n = (#v == 0) or tonumber(v) | ||
if not n then table.insert(invalid, argName(k)) end | if not n then table.insert(invalid, argName(k)) end | ||
elseif kind == "txt" then | elseif (kind == "grafika") or (kind == "grafika!") then | ||
if #v == 0 then table.insert(invalid, argName(k)) end | if findPlainHttp(v) then | ||
table.insert(nakedurl, argName(k)) | |||
else | |||
local g = checkImageName(v) | |||
if not g then table.insert(invalid, argName(k)) end | |||
end | |||
elseif (kind == "grafika?") or (kind == "grafika?!") then | |||
if findPlainHttp(v) then | |||
table.insert(nakedurl, argName(k)) | |||
else | |||
local g = (#v == 0) or checkImageName(v) | |||
if not g then table.insert(invalid, argName(k)) end | |||
end | |||
elseif (kind == "uri") or (kind == "uri!") then | |||
local u = checkUri(v) | |||
if not u then table.insert(invalid, argName(k)) end | |||
elseif (kind == "uri?") or (kind == "uri?!") then | |||
local u = (#v == 0) or checkUri(v) | |||
if not u then table.insert(invalid, argName(k)) end | |||
elseif (kind == "txt") or (kind == "txt!") then | |||
if #v == 0 then | |||
table.insert(invalid, argName(k)) | |||
elseif checkUri(v) then | |||
table.insert(nakedurl, argName(k)) | |||
elseif findPlainHttp(v) then | |||
table.insert(nakedurl, argName(k)) | |||
end | |||
elseif (kind == "text") or (kind == "text!") or (kind == "text?") then | |||
if ((kind ~= "text?") and (#v == 0)) then | |||
table.insert(invalid, argName(k)) | |||
elseif findFile(v) then | |||
table.insert(files, argName(k)) | |||
elseif checkUri(v) then | |||
table.insert(nakedurl, argName(k)) | |||
elseif findPlainHttp(v) then | |||
table.insert(nakedurl, argName(k)) | |||
end | |||
elseif kind == "old" then | elseif kind == "old" then | ||
table.insert(deprecated, argName(k)) | table.insert(deprecated, argName(k)) | ||
elseif kind == "uri*" then -- specjalny przpadek dla pola 'url' w [[Szablon:Cytuj]] | |||
local u = checkUri(v) or checkUri(mw.text.unstripNoWiki(v)) | |||
if not u then table.insert(invalid, argName(k)) end | |||
else | |||
local pattern = string.match(kind,"^(^.-$)!?$") | |||
if pattern and not mw.ustring.match(v, pattern) then | |||
table.insert(invalid, argName(k)) | |||
elseif (#v > 0) and checkUri(v) then | |||
table.insert(nakedurl, argName(k)) | |||
elseif findPlainHttp(v) then | |||
table.insert(nakedurl, argName(k)) | |||
end | |||
end | end | ||
end | |||
local missing = {} | |||
local suggested = {} | |||
mw.logObject(required, "required") | |||
for k, v in pairs(required) do | |||
table.insert(v and missing or suggested, k) | |||
end | |||
if (#missing == 0) and (#suggested == 0) and (#unknown == 0) and (#invalid == 0) and (#deprecated == 0) and (#nakedurl == 0) and (#files == 0) then | |||
return nil | |||
end | end | ||
local errorClasses = 0 | |||
-- generate messages for each category of problems | |||
local messages = {} | |||
if #invalid > 0 then | |||
errorClasses = errorClasses + 2 | |||
table.insert(messages, "Nieprawidłowe/puste pola: " .. mw.text.listToText(invalid) .. ".") | |||
end | end | ||
if (#missing > 0) or (#suggested > 0) then | |||
errorClasses = errorClasses + 1 | |||
if (#missing > 0) then table.insert(messages, "Brakujące pola: " .. mw.text.listToText(missing) .. ".") end | |||
if (#suggested > 0) then table.insert(messages, "Sugerowane pola (wstaw w kodzie): <code>" .. listToTplParams(suggested) .. "</code>") end | |||
end | end | ||
if #unknown > 0 then | |||
errorClasses = errorClasses + 4 | |||
table.insert(messages, "Nieznane pola: " .. mw.text.listToText(unknown) .. ".") | |||
end | end | ||
if # | if #deprecated > 0 then | ||
errorClasses = errorClasses + 8 | |||
table.insert(messages, "Przestarzałe pola: " .. mw.text.listToText(deprecated) .. ".") | |||
end | |||
if #nakedurl > 0 then | |||
errorClasses = errorClasses + 16 | |||
table.insert(messages, "Gołe linki: " .. mw.text.listToText(nakedurl) .. ".") | |||
end | |||
if #files > 0 then | |||
errorClasses = errorClasses + 32 | |||
table.insert(messages, "Nieoczekiwana grafika: " .. mw.text.listToText(files) .. ".") | |||
end | end | ||
if | -- nop? | ||
if templateName then | |||
showTemplate(templateName, frame:getParent().args) | |||
end | end | ||
if | -- render messages | ||
local message = mw.html.create() | |||
if emptyArg then | |||
message:wikitext("|=", emptyArg, "| ") | |||
end | |||
if infobox then | |||
message:wikitext("\n* ", table.concat(messages, "\n* ")) | |||
else | |||
message:wikitext(table.concat(messages, " ")) | |||
end | end | ||
message = tostring(message) | |||
-- result container | |||
local result = mw.html.create(infobox and "table" or "span") | |||
result:addClass("problemy") | |||
:addClass(class or nil) | |||
:attr("aria-hidden", "true") | |||
local restext = result | |||
if infobox then | |||
result:addClass("infobox") | |||
restext = result:tag("tr"):tag("td") | |||
else | |||
result:attr("data-nosnippet", "") | |||
end | |||
if templateName then | |||
restext:wikitext(showTemplate(templateName).." ") | |||
-- pomiń ten komunikat jeśli zabraknie tylko pól sugerowanych w infoboksie | |||
if not infobox or (errorClasses ~= 1) or (#missing > 0) then | |||
local warning = mw.html.create() | |||
warning:tag("code"):wikitext(showTemplate(templateName, frame:getParent().args)) | |||
warning:wikitext(" ") | |||
warning:tag("span"):addClass("problemy"):wikitext(message) | |||
mw.addWarning(tostring(warning)) | |||
end | |||
end | |||
restext:wikitext(message) | |||
if category then | if category then | ||
result:wikitext(category) | result:wikitext(category) | ||
end | |||
if infobox then | |||
if (errorClasses == 1) and (#missing <= 0) then | |||
result:addClass("tylko-braki") -- tylko SUGEROWANE braki | |||
end | |||
if (#missing > 0) or (#suggested > 0) then | |||
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "brakujące parametry").text, "]]") | |||
end | |||
if mw.title.getCurrentTitle().namespace == 0 then | |||
if #invalid > 0 then | |||
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "nieprawidłowe parametry").text, "]]") | |||
end | |||
if #unknown > 0 then | |||
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "nieznane parametry").text, "]]") | |||
end | |||
if #deprecated > 0 then | |||
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "przestarzałe parametry").text, "]]") | |||
end | |||
if #nakedurl > 0 then | |||
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "gołe linki").text, "]]") | |||
end | |||
if #files > 0 then | |||
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "grafika w nieodpowiednim miejscu").text, "]]") | |||
end | |||
end | |||
end | end | ||
return result | return nl..tostring(result) | ||
end, | end, | ||
Linia 254: | Linia 574: | ||
break | break | ||
end | end | ||
elseif mw.ustring.match(arg, "^OdeB ") then | |||
-- [[Ordre de Bataille]] | |||
elseif mw.ustring.match(arg, "^%u%l+%u") then | elseif mw.ustring.match(arg, "^%u%l+%u") then | ||
local justification = { | local justification = { | ||
Linia 263: | Linia 585: | ||
["Mc"] = true, | ["Mc"] = true, | ||
["Te"] = true, -- TeSelle | ["Te"] = true, -- TeSelle | ||
["Sar"] = true, -- SarDesai | |||
["Van"] = true, -- VanBuren | |||
["La"] = true, -- LaSalle | |||
} | } | ||
if not justification[mw.ustring.match(arg, "^%u%l+")] then | if not justification[mw.ustring.match(arg, "^%u%l+")] then | ||
Linia 297: | Linia 622: | ||
end | end | ||
local result = mw.html.create("span"):addClass("problemy-w-odn") | local result = mw.html.create("span") | ||
:addClass("problemy") | |||
:addClass("problemy-w-odn") | |||
if mw.title.getCurrentTitle().namespace == 0 then | if mw.title.getCurrentTitle().namespace == 0 then | ||
result:wikitext("[[Kategoria:Szablon odn do sprawdzenia]]") | result:wikitext("[[Kategoria:Szablon odn do sprawdzenia]]") | ||
end | end | ||
result:wikitext("ODN: ", problems) | result:wikitext("ODN: ", problems) | ||
return tostring(result) | return tostring(result) | ||
end, | |||
["Wikidane"] = function(frame) | |||
local property = frame.args.cecha | |||
local field = frame.args.pole | |||
local value = frame.args[1] | |||
if not property or not field then | |||
return | |||
end | |||
if not value then | |||
value = frame:getParent().args[field] | |||
if not value or (#value == 0) then | |||
return | |||
end | |||
end | |||
local entity = mw.wikibase.getEntity() | |||
if not entity or not entity.claims or not entity.claims[property] then | |||
return | |||
end | |||
for i, v in ipairs(entity.claims[property]) do | |||
if v.mainsnak.snaktype == "value" then | |||
if value == v.mainsnak.datavalue.value then | |||
return | |||
end | |||
end | |||
end | |||
local template = frame:getParent():getTitle() | |||
local infobox = mw.ustring.match(template, "^Szablon:(.- infobox)$") | |||
return mw.ustring.format("[[Kategoria:%s – niezgodność w Wikidanych – %s – %s]]", infobox and "Infoboksy" or "Szablony", infobox or template, field) | |||
end, | |||
["bez parametrów"] = function(frame) | |||
for k, v in pairs(frame:getParent().args) do | |||
return nil | |||
end | |||
return "tak" | |||
end, | end, | ||
["pole z hostem"] = function (frame) | |||
local host = frame.args.host | |||
if host and (#host > 0) then | |||
for k, v in pairs(frame:getParent().args) do | |||
local link = string.match(v, "[hH][tT][tT][pP][sS]?://[%S]+") | |||
if link then | |||
local uri = mw.uri.new(link) | |||
local valid, _ = mw.uri.validate(uri) | |||
if valid and uri.host and (#uri.host > 0) then | |||
if host == uri.host then | |||
mw.logObject({k, link}, "cały") | |||
return k | |||
end | |||
if #host < #uri.host then | |||
local s1 = '.'..host | |||
local s2 = string.sub(uri.host, -#s1) | |||
if s1 == s2 then | |||
mw.logObject({k, link}, "fragment") | |||
return k | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end | |||
end, | |||
["pola z autorami"] = function (frame) | |||
local result = {} | |||
local nazwisko = frame.args["nazwisko"] | |||
local imie = frame.args["imię"] | |||
local autor = frame.args["autor"] | |||
local link = frame.args["link"] | |||
local maxIndex = tonumber(frame.args["max"]) | |||
local prefix = frame.args["przed"] or "" | |||
local suffix = frame.args["po"] or "" | |||
for i = 1, maxIndex do | |||
local s = i == 1 and "" or tostring(i) | |||
local nin = string.gsub(nazwisko, '#', s) | |||
local iin = string.gsub(imie, '#', s) | |||
local ain = string.gsub(autor, '#', s) | |||
local lin = string.gsub(link, '#', s) | |||
local niv = frame:getParent().args[nin] | |||
local iiv = frame:getParent().args[iin] | |||
local aiv = frame:getParent().args[ain] | |||
local liv = frame:getParent().args[lin] | |||
local nis = niv and (#niv > 0) | |||
local iis = iiv and (#iiv > 0) | |||
local ais = aiv and (#aiv > 0) | |||
local lis = liv and (#liv > 0) | |||
local bad = (nis and ais) -- nazwisko -> zbędny autor | |||
or (nis and not iis) -- nazwisko bez imienia | |||
or (lis and not nis and not ais) -- tylko link | |||
or (iis and not nis) -- imię bez nazwiska | |||
if bad then | |||
table.insert(result, i) | |||
end | |||
end | |||
if #result > 0 then | |||
return prefix..mw.text.listToText(result)..suffix | |||
end | |||
end, | |||
["uri"] = function(frame) | |||
mw.logObject(frame:getParent():getTitle(), "parent:title") | |||
_ = mw.title.new("Moduł:Sprawdź/deprecated/uri").id | |||
local link = frame.args["link"] | |||
local space = frame.args["spacja"] | |||
local check = checkUri(link) | |||
if check then | |||
return link | |||
end | |||
return (space and (check ~= nil)) and link or "" | |||
end, | |||
--[[Sprawdzanie url do szablonów | |||
Wykorzystanie: | |||
{{#invoke:Sprawdź|url|{{{www|}}}|[{{{www}}} Strona internetowa]}} | |||
{{#invoke:Sprawdź|url|{{{www}}}|[{{{www}}} Strona internetowa]}} | |||
@param #1 Url do sprawdzenia. | |||
Ciąg typu "{{{abc}}}" pominie sprawdzenie, żeby pokazać wartość na stronie szablonu. | |||
@param #2 Tekst do wyświetlenia gdy OK. | |||
@return pusty string gdy błędny, "ok" lub zawartość #2 gdy OK. | |||
]] | |||
["url"] = function(frame) | |||
local link = frame.args[1] | |||
local okText = frame.args[2] or "ok" | |||
local isValid = string.find(link, '{{{') == 1 or checkUri(link) | |||
if isValid then | |||
return okText | |||
end | |||
return "" | |||
end, | |||
["lista nazw niepustych argumentów"] = function(frame) | |||
local argNames = {} | |||
for k, v in pairs(frame:getParent().args) do | |||
if #mw.text.trim(v) > 0 then | |||
table.insert(argNames, tostring(k)) | |||
end | |||
end | |||
return table.concat(argNames, ", ") | |||
end, | |||
["zapis daty dostępu"] = function(frame) | |||
local accessDate = frame:getParent().args["data dostępu"] | |||
if accessDate and (#accessDate > 0) then | |||
if not isDate20YYMMDD(accessDate) then | |||
local builder = mw.html.create('span') | |||
:addClass('problemy') | |||
:wikitext('zły zapis daty dostępu') | |||
if mw.title.getCurrentTitle().namespace == 0 then | |||
builder:wikitext('[[Kategoria:Szablon cytowania – zły zapis daty dostępu]]') | |||
end | |||
return builder | |||
end | |||
end | |||
end, | |||
} | } |
Wersja z 20:35, 3 kwi 2022
Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:Sprawdź/opis
local function checkUri(uri)
local urilen = #uri
for _,v in ipairs(mw.loadData("Moduł:Cytuj/dane").supportedUriSchemas) do
if (#v < urilen) and (string.lower(string.sub(uri,1, #v)) == v) then
return not string.match(uri, '%s')
end
end
end
function checkImageName(name)
if not name or (#name==0) or string.match(name, "[#<>%[%]|{}]") then
return false
end
local title = mw.title.makeTitle("Plik", name)
if not title then
return false
end
local res = {
prefix = {
plik = true,
image = true,
grafika = true,
file = true,
},
extension = {
jpg = true,
jpeg = true,
jpe = true,
png = true,
svg = true,
tif = true,
tiff = true,
gif = true,
xcf = true,
pdf = true,
djvu = true,
webp = true,
},
}
local prefix = string.match(name, "^:? *([^:]+) *:")
if prefix and res.prefix[string.lower(prefix)] then
return false
end
local extension = string.match(name, "%S.*%.([^%.]+)$")
return extension and res.extension[string.lower(extension)]
end
local function findPlainHttp(text)
if text then
text = mw.ustring.gsub(text, "%[[hH][tT][tT][pP][sS]?://%S+", "_")
return string.match(text, "[hH][tT][tT][pP][sS]?://%S")
end
end
local function findFile(text)
-- schowaj wyjątek: obrazek generowany przez Szablon:Link-interwiki
text = mw.ustring.gsub(text, "%[%[Plik:Wikidata%-logo%-en%.svg|10x9px|link=:d:Q%d+|Informacje powiązane z artykułem „.-” w Wikidanych%]%]", "")
-- normalize
text = mw.ustring.gsub(text, "%s*[Pp]lik%s*:%s*", "Plik:")
text = mw.ustring.gsub(text, "%s*[Ff]ile%s*:%s*", "Plik:")
text = mw.ustring.gsub(text, "%s*[Gg]rafika%s*:%s*", "Plik:")
text = mw.ustring.gsub(text, "%s*[Ii]mage%s*:%s*", "Plik:")
return mw.ustring.match(text, "%[%[Plik:([^%[%]|]+)[|%]]")
end
-- Lista of template params for wikicode. Like this:
-- | grafika = | data śmierci = | www =
local function listToTplParams(strArray)
return "| " .. table.concat(strArray, " = | ") .. " =";
end
local function showTemplate(templateName, args)
local result = {}
local flags = {}
table.insert(result, mw.text.nowiki("{{"))
if mw.isSubsting() then
table.insert(result, "subst:")
end
local title = mw.title.new(templateName)
if title.namespace ~= 10 then
table.insert(result, title.nsText)
table.insert(result, ":")
end
table.insert(result, title.text)
if args then
local i = 1
while args[i] do
table.insert(result, "|")
table.insert(result, mw.text.nowiki(args[i]))
i = i + 1
end
for k, v in pairs(args) do
local index = tonumber(k)
if (type(k) == "string") or (index and ((index < 1) or (index > i))) then
table.insert(result, "|")
table.insert(result, tostring(k))
table.insert(result, "=")
table.insert(result, mw.text.nowiki(v))
end
end
end
table.insert(result, mw.text.nowiki("}}"))
return table.concat(result)
end
local function infoboxCatTitle(infobox, class)
local catTitle = mw.title.makeTitle(14, "Infoboksy – "..class.." – "..infobox)
if not catTitle.exists then
mw.logObject(catTitle, "Dedykowana kategoria błędów w infoboksie nie istnieje")
catTitle = mw.title.makeTitle(14, "Infoboksy – "..class)
end
mw.logObject(catTitle, "infoboxCatTitle")
return catTitle
end
local function daysInMonth(year, month)
if month == 1 then return 31 end
if month == 2 then return ((year % 4) == 0) and 29 or 28 end
if month == 3 then return 31 end
if month == 4 then return 30 end
if month == 5 then return 31 end
if month == 6 then return 30 end
if month == 7 then return 31 end
if month == 8 then return 31 end
if month == 9 then return 30 end
if month == 10 then return 31 end
if month == 11 then return 30 end
if month == 12 then return 31 end
return 0
end
local function isDate20YYMMDD(date)
local y, m, d = mw.ustring.match(date, "^(20[0-9][0-9])%-([01][0-9])%-([0123][0-9])$")
local year = tonumber(y)
local month = tonumber(m)
local day = tonumber(d)
local result = year and month and day
and (year >= 2001)
and (month >= 1) and (month <= 12)
and (day >= 1) and (day <= daysInMonth(year, month))
if not result then
mw.logObject({date=date,year=year,month=month,day=day}, "isDate20YYMMDD")
end
return result
end
return {
["Porównaj"] = function(frame)
local config = frame:getParent().args[""] or ""
local options = mw.text.split(config, "|")
local templateName = mw.text.trim(options[1])
if #templateName == 0 then
local title = mw.title.getCurrentTitle()
if title.namespace == 10 then
templateName = mw.ustring.match(title.text, "^(.-)/opis")
or mw.ustring.match(title.text, "^(.-)/test")
or mw.ustring.match(title.text, "^(.-)/brudnopis")
or title.text
end
if #templateName == 0 then
mw.log("brak nazwy szablonu")
return
end
end
local templateTitle = mw.title.new(templateName, 10)
if templateTitle.id == 0 then
mw.log("szablon '"..templateName.."' nie istnieje")
return
end
local sandboxName = templateName.."/brudnopis"
local sandboxTitle = mw.title.new(sandboxName, 10)
if sandboxTitle.id == 0 then
mw.log("brudnopis '"..sandboxName.."' nie istnieje")
return
end
local i = 2
local showparams = true
local showinfo = true
local vertical = false
while i <= #options do
local option = mw.text.trim(options[i])
if option == "bez wikikodu" then
showparams = false
elseif option == "bez opisu" then
showinfo = false
elseif option == "pionowo" then
vertical = true
end
i = i + 1
end
local templateParams = {}
local params = {}
for k, v in pairs(frame:getParent().args) do
if k ~= "" then
templateParams[k] = v
table.insert(params, k)
end
end
local result = {}
table.insert(result, '<table style="width: 100%;">')
if showparams and (#params > 0) then
local compare = function(a, b)
-- return a < b
if (type(a) == "number") and (type(b) == "number") then
return a < b
end
if (type(a) == "string") and (type(b) == "string") then
return a < b
end
if (type(a) == "number") and (type(b) == "string") then
return true
end
return false
end
table.sort(params, compare)
table.insert(result, "<caption><code>{{")
table.insert(result, templateName)
for i, k in ipairs(params) do
table.insert(result, " | ")
local p = mw.text.nowiki(tostring(k))
local v = mw.text.nowiki(templateParams[k])
table.insert(result, p)
table.insert(result, " = ")
table.insert(result, v)
end
table.insert(result, "}}</code></caption>")
end
local templateResult = frame:expandTemplate{ title=templateName, args=templateParams}
local sandboxResult = frame:expandTemplate{ title=sandboxName, args=templateParams}
if templateResult and string.match(templateResult, "^{|") then
templateResult = "\n"..templateResult
end
if sandboxResult and string.match(sandboxResult, "^{|") then
sandboxResult = "\n"..sandboxResult
end
if vertical and showinfo then
table.insert(result, '<tr><th style="width: 15em">[[Szablon:')
table.insert(result, templateName)
table.insert(result, '|Szablon]]</th><td>')
table.insert(result, templateResult)
table.insert(result, '</td></tr><tr><th>[[Szablon:')
table.insert(result, sandboxName)
table.insert(result, '|Brudnopis szablonu]]</th><td>')
table.insert(result, sandboxResult)
table.insert(result, '</td></tr>')
elseif vertical then
table.insert(result, '<tr><td>')
table.insert(result, templateResult)
table.insert(result, '</td></tr><tr><td>')
table.insert(result, sandboxResult)
table.insert(result, '</td></tr>')
else
if showinfo then
table.insert(result, '<tr><th style="width: 50%;">[[Szablon:')
table.insert(result, templateName)
table.insert(result, '|Szablon]]</th><th style="width: 50%;">[[Szablon:')
table.insert(result, sandboxName)
table.insert(result, '|Brudnopis szablonu]]</th></tr>')
end
table.insert(result, '<tr style="vertical-align: top;"><td>')
table.insert(result, templateResult)
table.insert(result, '</td><td>')
table.insert(result, sandboxResult)
table.insert(result, '</td></tr>')
end
table.insert(result, "</table>")
return table.concat(result)
end,
["Parametry"] = function(frame)
if mw.title.getCurrentTitle().contentModel ~= "wikitext" then
mw.logObject(mw.title.getCurrentTitle().contentModel, "mw.title.getCurrentTitle().contentModel")
return -- to nie ma sensu w takim wypadku
end
local unknown = {}
local invalid = {}
local deprecated = {}
local nakedurl = {}
local files = {}
local templateName = frame:getParent():getTitle()
local infobox = mw.ustring.match(templateName, "^Szablon:(.- infobox)$")
local config = frame.args[""]
local class, space, category = string.match(config or "", "^%s*(%S+)(%s+)(.-)%s*$")
local nl = space and string.match(space, "\n") or ""
class = class or config
local function argName(arg)
return type(arg) ~= "string" and tostring(arg) or ('"'..arg..'"')
end
local required = {}
for k, v in pairs(frame.args) do
if mw.ustring.match(v, "!$") then
required[k] = true
if infobox then
-- odróżniaj pola sugerowane w infoboksach, które mogą być puste
if v == "!" or mw.ustring.match(v, "%?!$") then
required[k] = false
else
local pattern = string.match(v,"^(^.-$)!?$")
if pattern and mw.ustring.match("", pattern) then
required[k] = false
end
end
end
end
end
local emptyArg = false
for k, v in pairs(frame:getParent().args) do
required[k] = nil
local kind = frame.args[k]
if kind == "" or kind == "!" then
kind = "text?"
end
if k == "" then
emptyArg = v
elseif not kind then
table.insert(unknown, argName(k))
elseif (kind == "num") or (kind == "num!") then
local n = tonumber(v)
if not n then table.insert(invalid, argName(k)) end
elseif (kind == "num?") or (kind == "num?!") then
local n = (#v == 0) or tonumber(v)
if not n then table.insert(invalid, argName(k)) end
elseif (kind == "grafika") or (kind == "grafika!") then
if findPlainHttp(v) then
table.insert(nakedurl, argName(k))
else
local g = checkImageName(v)
if not g then table.insert(invalid, argName(k)) end
end
elseif (kind == "grafika?") or (kind == "grafika?!") then
if findPlainHttp(v) then
table.insert(nakedurl, argName(k))
else
local g = (#v == 0) or checkImageName(v)
if not g then table.insert(invalid, argName(k)) end
end
elseif (kind == "uri") or (kind == "uri!") then
local u = checkUri(v)
if not u then table.insert(invalid, argName(k)) end
elseif (kind == "uri?") or (kind == "uri?!") then
local u = (#v == 0) or checkUri(v)
if not u then table.insert(invalid, argName(k)) end
elseif (kind == "txt") or (kind == "txt!") then
if #v == 0 then
table.insert(invalid, argName(k))
elseif checkUri(v) then
table.insert(nakedurl, argName(k))
elseif findPlainHttp(v) then
table.insert(nakedurl, argName(k))
end
elseif (kind == "text") or (kind == "text!") or (kind == "text?") then
if ((kind ~= "text?") and (#v == 0)) then
table.insert(invalid, argName(k))
elseif findFile(v) then
table.insert(files, argName(k))
elseif checkUri(v) then
table.insert(nakedurl, argName(k))
elseif findPlainHttp(v) then
table.insert(nakedurl, argName(k))
end
elseif kind == "old" then
table.insert(deprecated, argName(k))
elseif kind == "uri*" then -- specjalny przpadek dla pola 'url' w [[Szablon:Cytuj]]
local u = checkUri(v) or checkUri(mw.text.unstripNoWiki(v))
if not u then table.insert(invalid, argName(k)) end
else
local pattern = string.match(kind,"^(^.-$)!?$")
if pattern and not mw.ustring.match(v, pattern) then
table.insert(invalid, argName(k))
elseif (#v > 0) and checkUri(v) then
table.insert(nakedurl, argName(k))
elseif findPlainHttp(v) then
table.insert(nakedurl, argName(k))
end
end
end
local missing = {}
local suggested = {}
mw.logObject(required, "required")
for k, v in pairs(required) do
table.insert(v and missing or suggested, k)
end
if (#missing == 0) and (#suggested == 0) and (#unknown == 0) and (#invalid == 0) and (#deprecated == 0) and (#nakedurl == 0) and (#files == 0) then
return nil
end
local errorClasses = 0
-- generate messages for each category of problems
local messages = {}
if #invalid > 0 then
errorClasses = errorClasses + 2
table.insert(messages, "Nieprawidłowe/puste pola: " .. mw.text.listToText(invalid) .. ".")
end
if (#missing > 0) or (#suggested > 0) then
errorClasses = errorClasses + 1
if (#missing > 0) then table.insert(messages, "Brakujące pola: " .. mw.text.listToText(missing) .. ".") end
if (#suggested > 0) then table.insert(messages, "Sugerowane pola (wstaw w kodzie): <code>" .. listToTplParams(suggested) .. "</code>") end
end
if #unknown > 0 then
errorClasses = errorClasses + 4
table.insert(messages, "Nieznane pola: " .. mw.text.listToText(unknown) .. ".")
end
if #deprecated > 0 then
errorClasses = errorClasses + 8
table.insert(messages, "Przestarzałe pola: " .. mw.text.listToText(deprecated) .. ".")
end
if #nakedurl > 0 then
errorClasses = errorClasses + 16
table.insert(messages, "Gołe linki: " .. mw.text.listToText(nakedurl) .. ".")
end
if #files > 0 then
errorClasses = errorClasses + 32
table.insert(messages, "Nieoczekiwana grafika: " .. mw.text.listToText(files) .. ".")
end
-- nop?
if templateName then
showTemplate(templateName, frame:getParent().args)
end
-- render messages
local message = mw.html.create()
if emptyArg then
message:wikitext("|=", emptyArg, "| ")
end
if infobox then
message:wikitext("\n* ", table.concat(messages, "\n* "))
else
message:wikitext(table.concat(messages, " "))
end
message = tostring(message)
-- result container
local result = mw.html.create(infobox and "table" or "span")
result:addClass("problemy")
:addClass(class or nil)
:attr("aria-hidden", "true")
local restext = result
if infobox then
result:addClass("infobox")
restext = result:tag("tr"):tag("td")
else
result:attr("data-nosnippet", "")
end
if templateName then
restext:wikitext(showTemplate(templateName).." ")
-- pomiń ten komunikat jeśli zabraknie tylko pól sugerowanych w infoboksie
if not infobox or (errorClasses ~= 1) or (#missing > 0) then
local warning = mw.html.create()
warning:tag("code"):wikitext(showTemplate(templateName, frame:getParent().args))
warning:wikitext(" ")
warning:tag("span"):addClass("problemy"):wikitext(message)
mw.addWarning(tostring(warning))
end
end
restext:wikitext(message)
if category then
result:wikitext(category)
end
if infobox then
if (errorClasses == 1) and (#missing <= 0) then
result:addClass("tylko-braki") -- tylko SUGEROWANE braki
end
if (#missing > 0) or (#suggested > 0) then
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "brakujące parametry").text, "]]")
end
if mw.title.getCurrentTitle().namespace == 0 then
if #invalid > 0 then
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "nieprawidłowe parametry").text, "]]")
end
if #unknown > 0 then
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "nieznane parametry").text, "]]")
end
if #deprecated > 0 then
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "przestarzałe parametry").text, "]]")
end
if #nakedurl > 0 then
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "gołe linki").text, "]]")
end
if #files > 0 then
result:wikitext("[[Kategoria:", infoboxCatTitle(infobox, "grafika w nieodpowiednim miejscu").text, "]]")
end
end
end
return nl..tostring(result)
end,
["odn"] = function(frame)
local pf = frame:getParent()
local i = 1
local problems = false
local yeardetected = false
while true do
local arg = pf.args[i]
if not arg then
problems = i == 1 and "brak argumentów" or false
break
end
if (i > 5) or yeardetected then
problems = "za dużo argumentów pozycyjnych"
break
end
if #arg == 0 then
problems = "pusty argument"
break
end
if arg ~= mw.text.trim(arg) then
problems = "nieoczekiwane odstępy na początku lub końcu argumentu"
break
end
if string.match(arg, "^%d+%l?$") then
yeardetected = true
if i == 1 then
problems = "rok musi być ostatnim parametrem po nazwiskach autorów"
break
end
elseif string.match(arg, "^s[%-%.:]%s*%d+") then
problems = "prawdopodobnie nieprawidłowo podany numer strony"
break
elseif string.match(arg, "%s%s") then
problems = "podwójne odstępy"
break
elseif mw.ustring.match(arg, "^%a+%d") then
if not mw.ustring.match(arg, "^[%u%d]+$") then
problems = "prawdopodobnie sklejone argumenty (brak pionowej kreski)"
break
end
elseif mw.ustring.match(arg, "^OdeB ") then
-- [[Ordre de Bataille]]
elseif mw.ustring.match(arg, "^%u%l+%u") then
local justification = {
["De"] = true,
["Del"] = true,
["Di"] = true,
["Le"] = true,
["Mac"] = true,
["Mc"] = true,
["Te"] = true, -- TeSelle
["Sar"] = true, -- SarDesai
["Van"] = true, -- VanBuren
["La"] = true, -- LaSalle
}
if not justification[mw.ustring.match(arg, "^%u%l+")] then
problems = "prawdopodobnie sklejone argumenty (brak pionowej kreski)"
break
end
end
i = i + 1
end
if not problems then
local odn = pf.args.odn
if odn and ((#odn ~= 1) or (odn < "a") or (odn > "z")) then
problems = "nieoczekiwany parametr odn"
end
end
if not problems then
local s = pf.args.s
if s and string.match(s, "&[a-z]+;") then
problems = "użyto encji HTML w numerze strony"
end
end
if not problems then
if pf.args.strona or pf.args.ss or pf.args.strony or pf.args.p or pf.args.page or pf.args.pp or pf.args.pages then
problems = "przestarzały parametr z numerem strony"
end
end
if not problems then
return nil
end
local result = mw.html.create("span")
:addClass("problemy")
:addClass("problemy-w-odn")
if mw.title.getCurrentTitle().namespace == 0 then
result:wikitext("[[Kategoria:Szablon odn do sprawdzenia]]")
end
result:wikitext("ODN: ", problems)
return tostring(result)
end,
["Wikidane"] = function(frame)
local property = frame.args.cecha
local field = frame.args.pole
local value = frame.args[1]
if not property or not field then
return
end
if not value then
value = frame:getParent().args[field]
if not value or (#value == 0) then
return
end
end
local entity = mw.wikibase.getEntity()
if not entity or not entity.claims or not entity.claims[property] then
return
end
for i, v in ipairs(entity.claims[property]) do
if v.mainsnak.snaktype == "value" then
if value == v.mainsnak.datavalue.value then
return
end
end
end
local template = frame:getParent():getTitle()
local infobox = mw.ustring.match(template, "^Szablon:(.- infobox)$")
return mw.ustring.format("[[Kategoria:%s – niezgodność w Wikidanych – %s – %s]]", infobox and "Infoboksy" or "Szablony", infobox or template, field)
end,
["bez parametrów"] = function(frame)
for k, v in pairs(frame:getParent().args) do
return nil
end
return "tak"
end,
["pole z hostem"] = function (frame)
local host = frame.args.host
if host and (#host > 0) then
for k, v in pairs(frame:getParent().args) do
local link = string.match(v, "[hH][tT][tT][pP][sS]?://[%S]+")
if link then
local uri = mw.uri.new(link)
local valid, _ = mw.uri.validate(uri)
if valid and uri.host and (#uri.host > 0) then
if host == uri.host then
mw.logObject({k, link}, "cały")
return k
end
if #host < #uri.host then
local s1 = '.'..host
local s2 = string.sub(uri.host, -#s1)
if s1 == s2 then
mw.logObject({k, link}, "fragment")
return k
end
end
end
end
end
end
end,
["pola z autorami"] = function (frame)
local result = {}
local nazwisko = frame.args["nazwisko"]
local imie = frame.args["imię"]
local autor = frame.args["autor"]
local link = frame.args["link"]
local maxIndex = tonumber(frame.args["max"])
local prefix = frame.args["przed"] or ""
local suffix = frame.args["po"] or ""
for i = 1, maxIndex do
local s = i == 1 and "" or tostring(i)
local nin = string.gsub(nazwisko, '#', s)
local iin = string.gsub(imie, '#', s)
local ain = string.gsub(autor, '#', s)
local lin = string.gsub(link, '#', s)
local niv = frame:getParent().args[nin]
local iiv = frame:getParent().args[iin]
local aiv = frame:getParent().args[ain]
local liv = frame:getParent().args[lin]
local nis = niv and (#niv > 0)
local iis = iiv and (#iiv > 0)
local ais = aiv and (#aiv > 0)
local lis = liv and (#liv > 0)
local bad = (nis and ais) -- nazwisko -> zbędny autor
or (nis and not iis) -- nazwisko bez imienia
or (lis and not nis and not ais) -- tylko link
or (iis and not nis) -- imię bez nazwiska
if bad then
table.insert(result, i)
end
end
if #result > 0 then
return prefix..mw.text.listToText(result)..suffix
end
end,
["uri"] = function(frame)
mw.logObject(frame:getParent():getTitle(), "parent:title")
_ = mw.title.new("Moduł:Sprawdź/deprecated/uri").id
local link = frame.args["link"]
local space = frame.args["spacja"]
local check = checkUri(link)
if check then
return link
end
return (space and (check ~= nil)) and link or ""
end,
--[[Sprawdzanie url do szablonów
Wykorzystanie:
{{#invoke:Sprawdź|url|{{{www|}}}|[{{{www}}} Strona internetowa]}}
{{#invoke:Sprawdź|url|{{{www}}}|[{{{www}}} Strona internetowa]}}
@param #1 Url do sprawdzenia.
Ciąg typu "{{{abc}}}" pominie sprawdzenie, żeby pokazać wartość na stronie szablonu.
@param #2 Tekst do wyświetlenia gdy OK.
@return pusty string gdy błędny, "ok" lub zawartość #2 gdy OK.
]]
["url"] = function(frame)
local link = frame.args[1]
local okText = frame.args[2] or "ok"
local isValid = string.find(link, '{{{') == 1 or checkUri(link)
if isValid then
return okText
end
return ""
end,
["lista nazw niepustych argumentów"] = function(frame)
local argNames = {}
for k, v in pairs(frame:getParent().args) do
if #mw.text.trim(v) > 0 then
table.insert(argNames, tostring(k))
end
end
return table.concat(argNames, ", ")
end,
["zapis daty dostępu"] = function(frame)
local accessDate = frame:getParent().args["data dostępu"]
if accessDate and (#accessDate > 0) then
if not isDate20YYMMDD(accessDate) then
local builder = mw.html.create('span')
:addClass('problemy')
:wikitext('zły zapis daty dostępu')
if mw.title.getCurrentTitle().namespace == 0 then
builder:wikitext('[[Kategoria:Szablon cytowania – zły zapis daty dostępu]]')
end
return builder
end
end
end,
}