Moduł:Cytuj: Różnice pomiędzy wersjami

Z VatoWiki
Przejdź do nawigacji Przejdź do wyszukiwania
m 1 wersja
 
m 1 wersja
 
(Nie pokazano 1 wersji utworzonej przez jednego użytkownika)
Linia 1: Linia 1:
local resources = {
local resources = mw.loadData("Moduł:Cytuj/dane")
modes = { "auto", "książkę", "pismo", "stronę" },
local access = mw.loadData("Moduł:Cytuj/dostęp")
COinS = {
false,                          -- auto
"info:ofi/fmt:kev:mtx:book",    -- książkę
"info:ofi/fmt:kev:mtx:journal", -- pismo
"info:ofi/fmt:kev:mtx:journal", -- stronę
},


categories = {
local function checkUri(uri)
empty = "[[Kategoria:Szablon cytowania bez parametrów]]",
local urilen = #uri
undetermined = "[[Kategoria:Szablon cytowania bez określonego trybu]]",
for _,v in ipairs(resources.supportedUriSchemas) do
missingArg = "[[Kategoria:Szablon cytowania w trybie 'cytuj %s' bez obowiązkowych parametrów]]",
if (#v < urilen) and (string.lower(string.sub(uri,1, #v)) == v) then
suspectedComma = "[[Kategoria:Szablon cytowania zawiera przecinek w polu z opisem autora]]",
return not string.match(uri, '%s')
unusedUrl = "[[Kategoria:Szablon cytowania zawiera nieużywany URL]]",
end
unusedPublished = "[[Kategoria:Szablon cytowania zawiera pola 'opublikowany' i 'wydawca']]",
end
sameJournalAndPublished = "[[Kategoria:Szablon cytowania zawiera identyczne pola 'czasopismo' i 'opublikowany']]",
end
},
--[[
; name : name of the parameter used in the template
; used : indicator whether the parameter is used in specific citation mode
list of modes is declared in variable 'modes' at the top of the module
the first entry is reserved for automatic full citation mode, which accepts all parameters
; "!" : mandatory
; false : not used
; ''otherwise'' : optional
; "+" : only in one mode, and written differently for easier notice
; "*" : additional support in the code (in url and published for now)
--]]
params = {
chapterauthor = {
name = "autor r",
used = { true, "+", false, false, },
},
chapter = {
name = "rozdział",
used = { true, "+", false, false, },
},
author = {
name = "autor",
used = { true, true, true, true, },
},
editor = {
name = "redaktor",
used = { true, true, true, true, },
},
url = {
name = "url",
used = { true, true, true, "*", },
},
title = {
name = "tytuł",
used = { true, "!", true, "!", },
},
others = {
name = "inni",
used = { true, "+", false, false, },
},
work = {
name = "praca",
used = { true, false, false, "+", },
},
journal = {
name = "czasopismo",
used = { true, false, "!", false, },
},
mediatype = {
name = "typ nośnika",
used = { true, true, true, true, },
},
responsibility = {
name = "odpowiedzialność",
used = { true, false, "+", false, },
},
issue = {
name = "wydanie",
used = { true, true, true, false, },
},
description = {
name = "opis",
used = { true, "+", false, false, },
},
place = {
name = "miejsce",
used = { true, true, true, false, },
},
published = {
name = "opublikowany",
used = { true, "*", "*", "*", },
},
publisher = {
name = "wydawca",
used = { true, true, true, false, },
},
date = {
name = "data",
used = { true, true, true, true, },
},
p = {
name = "s",
used = { true, true, true, true, },
},
doi = {
name = "doi",
used = { true, true, true, false, },
},
isbn = {
name = "isbn",
used = { true, "+", false, false, },
},
lccn = {
name = "lccn",
used = { true, "+", false, false, },
},
issn = {
name = "issn",
used = { true, true, true, false, },
},
pmid = {
name = "pmid",
used = { true, false, "+", false, },
},
pmc = {
name = "pmc",
used = { true, false, "+", false, },
},
bibcode = {
name = "bibcode",
used = { true, false, "+", false, },
},
oclc = {
name = "oclc",
used = { true, true, true, false, },
},
arxiv = {
name = "arxiv",
used = { true, false, false, true, },
},
id = {
name = "id",
used = { true, true, true, true, },
},
accessdate= {
name = "data dostępu",
used = { true, true, true, true, },
},
archive = {
name = "archiwum",
used = { true, true, true, true, },
},
archived = {
name = "zarchiwizowano",
used = { true, true, true, true, },
},
quotation = {
name = "cytat",
used = { true, true, true, true, },
},
lang = {
name = "język",
used = { true, true, true, true, },
},
odn = {
name = "odn",
used = { true, true, true, true, },
},
},
 
monthparser = {
["styczeń"] = 1,      ["stycznia"] = 1,      ["sty"] = 1,  ["i"] = 1,
["luty"] = 2,        ["lutego"] = 2,        ["lut"] = 2,  ["ii"] = 2,
["marzec"] = 3,      ["marca"] = 3,        ["mar"] = 3,  ["iii"] = 3,
["kwiecień"] = 4,    ["kwietnia"] = 4,      ["kwi"] = 4,  ["iv"] = 4,
["maj"] = 5,          ["maja"] = 5,                        ["v"] = 5,
["czerwiec"] = 6,    ["czerwca"] = 6,      ["cze"] = 6,  ["vi"] = 6,
["lipiec"] = 7,      ["lipca"] = 7,        ["lip"] = 7,  ["vii"] = 7,
["sierpień"] = 8,    ["sierpnia"] = 8,      ["sie"] = 8,  ["viii"] = 8,
["wrzesień"] = 9,    ["września"] = 9,      ["wrz"] = 9,  ["ix"] = 9,
["październik"] = 10, ["października"] = 10, ["paź"] = 10, ["x"] = 10,
["listopad"] = 11,    ["listopada"] = 11,    ["lis"] = 11, ["xi"] = 11,
["grudzień"] = 12,    ["grudnia"] = 12,      ["gru"] = 12, ["xii"] = 12,
},
 
months = {
[1]  = { m="styczeń",    d="stycznia", },
[2]  = { m="luty",        d="lutego", },
[3]  = { m="marzec",      d="marca", },
[4]  = { m="kwiecień",    d="kwietnia", },
[5]  = { m="maj",        d="maja", },
[6]  = { m="czerwiec",    d="czerwca", },
[7]  = { m="lipiec",      d="lipca", },
[8]  = { m="sierpień",    d="sierpnia", },
[9]  = { m="wrzesień",    d="września", },
[10] = { m="październik", d="października", },
[11] = { m="listopad",    d="listopada", },
[12] = { m="grudzień",    d="grudnia", },
},
exactAuthors = {
["Praca zbiorowa"] = true,
["[[Gall Anonim]]"] = true,
}
}


local function softNoWiki(text)
local function softNoWiki(text)
local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = "&#x22;", ["'"] = "&#x27;", ["["] = "&#x5B;", ["]"] = "&#x5D;", ["{"] = "&#x7B;", ["|"] = "&#x7C;", ["}"] = "&#x7D;"})
local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = "&#x22;", ["'"] = "&#x27;", ["["] = "&#x5B;", ["]"] = "&#x5D;", ["{"] = "&#x7B;", ["|"] = "&#x7C;", ["}"] = "&#x7D;"})
-- przywróc [[szablon:J]] z kursywą tak/nie
result, count = string.gsub(result, "<span +style=&#x22;font%-style: ?([a-z]+);?&#x22; +lang=&#x22;([a-z%-]+)&#x22; *>", "<span style=\"font-style: %1;\" lang=\"%2\">")
-- przywróc [[szablon:J]] goły
result, count = string.gsub(result, "<span +lang=&#x22;([a-z%-]+)&#x22; *>", "<span lang=\"%1\">")
-- przywróć nowiki
result, count = string.gsub(result, "\127&#x27;&#x22;`UNIQ%-%-(nowiki%-[0-9A-F]+)%-QINU`&#x22;&#x27;\127", "\127'\"`UNIQ--%1-QINU`\"'\127")
return result
return result
end
end
Linia 218: Linia 30:
local result, count = string.gsub(text, "</?[Ss][Pp][Aa][Nn][^>]*>", "")
local result, count = string.gsub(text, "</?[Ss][Pp][Aa][Nn][^>]*>", "")
return result
return result
end
local function first(data)
return type(data) == "table" and data[1] or data
end
end


Linia 250: Linia 66:
end
end
end
end
 
if count == 1 then
for i, v in ipairs(detector) do
if detector[i] then
return i, resources.COinS[i]
end
end
end
if detector[4] -- web?
and p.args[resources.params.url.name]
then
-- promote to web but without COinS
return 4, false
end
for i, v in ipairs(detector) do
for i, v in ipairs(detector) do
if detector[i] then
if detector[i] then
-- the type is succesfully determined
-- if type is determined more than once
-- but in case more than one is possible
-- use only the first one without COinS
-- use only the first one
return i, false
-- include COinS format if this is the only determined type
return i, count == 1 and resources.COinS[i] or false
end
end
end
end
Linia 293: Linia 122:


return false
return false
end
authorMethodtable.isIlustrator = function(author)
return checkPatterns(author, {"il%.?", "ilus%.?", "ilustrator" }, {"[%(%[]il%.?[%)%]]", "[%(%[]ilus%.?[%)%]]", "[%(%[]ilustrator[%)%]]" })
end
authorMethodtable.isTranslator = function(author)
return checkPatterns(author, {"tłum%.?", "tłumacz" }, {"[%(%[]tłum%.?[%)%]]", "[%(%[]tłumacz[%)%]]" })
end
authorMethodtable.isEditor = function(author)
return checkPatterns(author, {"red%.?", "redaktor", "pod red%.?", "pod redakcją" }, {"[%(%[]red%.?[%)%]]", "[%(%[]redaktor[%)%]]" })
end
authorMethodtable.isDeveloper = function(author)
return checkPatterns(author, {"oprac%.?", "opracowała?" }, {"[%(%[]oprac%.?[%)%]]", "[%(%[]opracowała?[%)%]]" })
end
end


Linia 334: Linia 147:
end
end
if initials then
if initials then
before:tag("span"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
before:tag("span"):css("display", "none"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
end
end
before:wikitext("&nbsp;")
before:wikitext("&nbsp;")
Linia 342: Linia 155:


if not namefirst and (name or initials) then
if not namefirst and (name or initials) then
local after = data.familynamefirst and builder or builder:tag("span"):addClass("cite-name-after")
local after = data.familynamefirst and builder or builder:tag("span"):css("display", "none"):addClass("cite-name-after")
after:wikitext("&nbsp;")
after:wikitext("&nbsp;")
if name then
if name then
Linia 350: Linia 163:
after:tag("span"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
after:tag("span"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
end
end
if data.js then
after:wikitext(",")
end
end
if data.js then
builder:wikitext("&nbsp;", data.js)
end
end
Linia 378: Linia 198:


local function makeInitials(name)
local function makeInitials(name)
local nameinitials = mw.ustring.gsub(name, "(%w[Hh]?)([%w%-%.]+)%s*", "%1. ")
local nameinitials = mw.ustring.gsub(name, "(%w[Hh]?)[%w]*%.?([%s%-–—]?)%s*", "%1. ") -- zostaw początki słów (jedna litera + opcjonalne następujące 'h')
nameinitials = mw.ustring.gsub(nameinitials, "%f[%w]%l%.%s", "")
nameinitials = mw.ustring.gsub(nameinitials, "%f[%w]%l%.%s", "")               -- usuń inicjały z małych liter
nameinitials = mw.ustring.gsub(nameinitials, "([^C%W])[Hh]%.%s", "%1. ")
nameinitials = mw.ustring.gsub(nameinitials, "([^C%W])[Hh]%.?%s", "%1. ")      -- usuń drugie 'h' jeśli nie zaczyna się na 'C'
nameinitials = mw.ustring.gsub(nameinitials, "(%u[Hh]?)[%.%s]*", "%1.")       -- dodaj brakujące kropki i usuń zbędne spacje
return mw.text.trim(nameinitials)
return mw.text.trim(nameinitials)
end
local function fixInitials(name)
local result, _ = mw.ustring.gsub(name, "^(%uh?)%.?%s+(%uh?)%.", "%1.%2.") -- popraw inicjały na początku
result, _ = mw.ustring.gsub(result, "%f[%a](%uh?)%.%s+(%uh?)%.", "%1.%2.") -- popraw inicjały w środku
result, _ = mw.ustring.gsub(result, "%f[%a](%uh?)%.%s+(%uh?)%.", "%1.%2.") -- popraw kolejne inicjały w środku
return result
end
local function isInQuotes(text)
if (string.len(text) < 2) then
return false;
end
local tstart = text:sub(1, 1);
if (tstart ~= '"') then
return false;
end
local tend = text:sub(-1);
if (tend ~= '"') then
return false;
end
return true; 
end
end


local function parseAuthor(author)
local function parseAuthor(author)
local result = {}
local result = {}
if string.match(author, "\127") then -- wpisy z <nowiki> nie są analizowane
result.exact = author
setmetatable(result, authorMetatable)
return result
end
local author = mw.text.trim(author)
local author = mw.text.trim(author)
local a = string.gsub(author, "\\[\\%.:]", { ["\\\\"]="\\", ["\\."]=",", ["\\:"]=";", })
if a ~= author then
result.exact = a
setmetatable(result, authorMetatable)
return result
end
if resources.exactAuthors[author] then
if resources.exactAuthors[author] then
result.exact = author
result.exact = author
Linia 420: Linia 278:
end
end


local prefix, rest = mw.ustring.match(author, "^([%l%p%s]+)(.+)$")
local prefix1, rest = mw.ustring.match(author, "^([%l%p%s]+)(.+)$")
if not prefix then
if not prefix1 then
rest = author
rest = author
prefix = ""
prefix1 = ""
end
end


prefix = mw.text.trim(prefix0.." "..prefix)
local prefix = mw.text.trim(prefix0.." "..prefix1)
if #prefix > 0 then
if #prefix > 0 then
if mw.ustring.sub(prefix, -1) == "#" then
if mw.ustring.sub(prefix, -1) == "#" then
Linia 446: Linia 304:
if #suffix > 0 then
if #suffix > 0 then
result.suffix = mw.ustring.gsub(suffix, "%s+", " ") -- collapse spaces
result.suffix = mw.ustring.gsub(suffix, "%s+", " ") -- collapse spaces
suffix = " "..result.suffix
for i, v in ipairs(resources.js) do
if mw.ustring.match(suffix, v[1]) then
result.suffix = mw.text.trim(mw.ustring.gsub(suffix, v[1], ""))
result.js = v[2]
break
end
end
else
for i, v in ipairs(resources.js) do
if mw.ustring.match(rest2, v[1]) then
rest2 = mw.text.trim(mw.ustring.gsub(rest2, v[1], ""))
result.js = v[2]
break
end
end
end
end
 
local lastname, name = mw.ustring.match(rest2, "%s*([^,]-)%s*,%s*(.-)%s*$")
local lastname, name = mw.ustring.match(rest2, "%s*([^,]-)%s*,%s*(.-)%s*$")
if not lastname then
if not lastname then
Linia 453: Linia 327:
lastname, name = mw.ustring.match(rest2, "%s*(%u[%l%d%p]*)%s+(.-)%s*$")
lastname, name = mw.ustring.match(rest2, "%s*(%u[%l%d%p]*)%s+(.-)%s*$")
else
else
name, lastname = mw.ustring.match(rest2, "%s*(.-)%s+(%u[%w%p]-)%s*$")
local prefix2
name, lastname, prefix2 = mw.ustring.match(rest2, "%s*(.-)%s+((%l[%l%p]%l?)%u[%w%p]-)%s*$")
if not resources.lastnamePrefixes[prefix2] then
name, lastname = mw.ustring.match(rest2, "%s*(.-)%s+(%u[%w%p]-)%s*$")
end
end
end
elseif resources.lastnamePrefixes[prefix1] then
lastname = prefix1 .. lastname
elseif resources.lastnamePrefixes[prefix1] == false then
name = name.." "..mw.text.trim(prefix1)
end
end
Linia 460: Linia 342:
result.lastname = mw.text.trim(rest2)
result.lastname = mw.text.trim(rest2)
else
else
result.name = name
result.name = fixInitials(name)
result.lastname = lastname
result.lastname = lastname
result.nameinitials = makeInitials(name)
result.nameinitials = makeInitials(name)
Linia 583: Linia 465:
end
end


local function loadAuthor(frame, params, index)
local function collectAuthors(author, checkForAltFormat)
local argAuthor = formatDynamicArgName(params.author.name, index)
if not author then
 
return
local result = false
local author = frame.args[argAuthor]
if author and (#author > 0) then
result = parseAuthor(author)
end
end
 
if not result then
-- Obsługa cudzysłowów w autorach (treat quoted authors as-is)
return
if (isInQuotes(mw.text.trim(author))) then
local strippedAuthor = mw.text.trim(author, '"\t\r\n\f ')
return { items = {strippedAuthor}, more=false, comma=false, etal=false, separator="" }
end
end
 
local first = frame.args[argFirst]
if first and (#first > 0) then
function findUtf8CharAt(text, at)
result.name = first
local back = false
result.nameinitials = makeInitials(first)
if at < 0 then
at = #text + at + 1
back = true
end
while at > 1 do
local b = string.byte(text, at, at)
if (b < 128) or (b >= 192) then
break
end
at = at - 1
end
return back and at - #text - 1 or at
end
end
local link = frame.args[argLink]
local etal = false
if link and (#link > 0) then
local authorTail = #author <= 50 and author or string.sub(author, findUtf8CharAt(author, -50))
result.link = link
for i, p in ipairs(resources.etalPatterns) do
local a, e = string.match(authorTail, p)
if a then
author = string.sub(author, 1, #author-#e)
etal = e
break
end
end
end
return result
function decodeEntity(s)
end
local result = nil
 
local hex = string.match(s, "^&#[xX]([0-9A-Fa-f]+);$")
local function collectAuthors(author)
if hex then
if not author then
result = mw.ustring.char(tonumber(hex, 16))
return
else
local dec = string.match(s, "^&#([0-9]+);$")
if dec then
result = mw.ustring.char(tonumber(dec, 10))
elseif resources.htmlEntities[s] then
result = mw.ustring.char(resources.htmlEntities[s])
else
return string.gsub(s, ";", "\\:")
end
end
if result == ";" then
return "\\:"
elseif result == "," then
return "\\."
elseif result == "\\" then
return "\\\\"
else
return result
end
end
end
local authorHead = #author <= 500 and author or string.sub(author, 1, findUtf8CharAt(author, 500) - 1)
local result = {}
local result = {}
local splitter = string.match(author, ";") and ";" or ","
local esc1 = string.gsub(authorHead, "\\", "\\\\")
local authors = mw.text.split(author, splitter, true)
local esc2 = string.gsub(esc1, "&#?[a-zA-Z0-9]+;", decodeEntity)
for _, v in ipairs(authors) do
local splitter = string.match(esc2, ";") and ";" or ","
local authors = mw.text.split(esc2, splitter.."%s*", false)
local nth = false
local count = #authors
if (#authorHead < #author) and (count > 4) then
if count > 5 then
table.remove(authors, count)
count = count - 1
end
local at, _ = string.find(authorHead, authors[count], 1, true)
nth = string.sub(author, at)
table.remove(authors, count)
count = count - 1
end
local alt = false
if (splitter == ",") and checkForAltFormat then
local altAuthors = {}
alt = true
for i, v in ipairs(authors) do
local n0 = ""
local s, n = mw.ustring.match(v, "^(%u%l+)%s(%u+)%.?$")
if not s then
s, n = mw.ustring.match(v, "^(%u%l+[%s%-–]%u%l+)%s(%u+)%.?$")
end
if not s then
n0, s, n = mw.ustring.match(v, "^(%l%l%l?)%s(%u%l+)%s(%u+)%.?$") -- de, von, van, der etc.
end
if not s then
alt = false
break
end
local initials, _ = mw.ustring.gsub(n, "(%u)", "%1.")
if #n0 > 0 then
n0 = " "..n0
end
table.insert(altAuthors, s..", "..initials..n0)
end
if alt then
authors = altAuthors
splitter = ";"
end
end
for i, v in ipairs(authors) do
local author = parseAuthor(v)
local author = parseAuthor(v)
if author then
if author then
Linia 629: Linia 595:
end
end
return result, (#result == 2) and (separator == ",")
local check = false
if alt then
check = "alt"
elseif (#result == 2) and (splitter == ",") then
check = not result[1].link and not result[1].exact and not result[1].name
or not result[2].link and not result[2].exact and not result[2].name
if check then
if result[1].lastname and not result[1].name and not result[2].exact
and not mw.ustring.match(result[1].lastname, "%S%s+%S") then
local oneAuthor = parseAuthor(author)
if oneAuthor then
table.remove(result,2)
result[1] = oneAuthor
check = false
end
end
end
if check then
mw.logObject(result,"przecinek u autora")
end
end
return { items = result, more=nth, comma = check, etal = etal, separator=splitter.." " }
end
end
local function formatAuthors(authors, useDecorations, nextgroup)
local function formatAuthors(authors, useDecorations, nextgroup, etalForm)
local count = #authors
local count = #authors.items
if count == 0 then
if count == 0 then
return nil
return nil, false
end
local suffix = function(author)
if useDecorations then
for _, v in ipairs(resources.authorFunc) do
if checkPatterns(author, v.prefixes, v.suffixes) then
return v.append
end
end
end
return ""
end
end
Linia 641: Linia 641:
local a = author:format(nextgroup)
local a = author:format(nextgroup)
local r = author.link and ("[["..author.link.."|"..a.."]]") or a
local r = author.link and ("[["..author.link.."|"..a.."]]") or a
local s = useDecorations and (author:isEditor() and " (red.)" or (author:isTranslator() and " (tłum.)" or (author:isIlustrator() and " (ilust.)" or (author:isDeveloper() and " (oprac.)" or "")))) or ""
return r..suffix(author)
return r..s
end
end
if count == 1 then
if count == 1 then
return formatter(authors[1])
local a1 = formatter(authors.items[1])
local etal = authors.etal and (etalForm or " i inni") or ""
return a1..etal, false
end
end
local result = {}
local result = {}
table.insert(result, formatter(authors[1]))
table.insert(result, formatter(authors.items[1]))
if not authors.etal and (count <= 3) then
if count <= 3 then
table.insert(result, ", ");
table.insert(result, ", ");
table.insert(result, formatter(authors[2]))
table.insert(result, formatter(authors.items[2]))
if count == 3 then
if count == 3 then
table.insert(result, ", ");
table.insert(result, ", ");
table.insert(result, formatter(authors[3]))
table.insert(result, formatter(authors.items[3]))
end
end
return table.concat(result, "")
return table.concat(result, ""), false
end
 
local title = {}
for i = 1, count do
table.insert(title, authors.items[i]:towiki()..suffix(authors.items[i]))
end
if authors.more then
table.insert(title, authors.more)
end
end
table.insert(result, "<span class=\"cite-more-full\">")
table.insert(result, "<span class=\"cite-at-al\" title=\"")
local title = {}
table.insert(result, table.concat(title, authors.separator))
for i = 2, count do
if authors.etal then
table.insert(result, ", ");
table.insert(result, etalForm or " i inni")
table.insert(result, formatter(authors[i]))
table.insert(title, authors[i]:towiki())
end
end
table.insert(result, "\">")
table.insert(result, etalForm or " i inni")
table.insert(result, "</span>")
table.insert(result, "</span>")
table.insert(result, "<span class=\"cite-at-al\" title=\"")
return table.concat(result, ""), true
table.insert(result, table.concat(title, ", "))
table.insert(result, "\"> i inni</span>")
return table.concat(result, "")
end
end


Linia 706: Linia 711:
end
end
local link, description = mw.ustring.match(text, "^%[([hH][tT][tT][pP][sS]?://%S*)%s+(.-)%]$")
local link, description = mw.ustring.match(text, "^%[(%S*)%s+(.-)%]$")
if link then
if link and checkUri(link) then
return description, false, link
return description, false, link
end
end
Linia 715: Linia 720:


local function detectArchive(url)
local function detectArchive(url)
local y, m, d, link = mw.ustring.match(url, "^https?://web%.archive%.org/web/(%d%d%d%d)(%d%d)(%d%d)%d%d%d%d%d%d/(https?://.*)$")
local defaultDecoder = resources.archiveDecoders.defaultDecoder
if y then
for i, v in ipairs(resources.archiveDecoders) do
return link, y.."-"..m.."-"..d
local pattern = type(v) == "string" and v or v.pattern
local decoder = type(v) == "table" and v or defaultDecoder
local items = { mw.ustring.match(url, pattern) }
if #items > 0 then
return items[decoder.link], items[decoder.year].."-"..items[decoder.month].."-"..items[decoder.day]
end
end
end
return false, false
return false, false
end
local function isAutoGeneratedUrl(url)
local address = string.gsub(url, "^https?:", "")
for k, v in pairs(resources.params) do
if v.link then
local links = type(v.link) == "table" and v.link or { v.link }
for _, vlink in ipairs(links) do
local prefix = string.gsub(vlink, "^https?:", "")
if (#address > #prefix) and (string.sub(address, 1, #prefix) == prefix) then
return true
end
end
end
end
return false
end
end


Linia 743: Linia 770:
result.missing = v.name
result.missing = v.name
end
end
end
end
end
-- check url argument
if result.url == "nie" then
result.url = false
elseif result.url then
if not checkUri(result.url) then
local unstrip = mw.text.unstripNoWiki( result.url )
result.url = false
if unstrip then
result.urlnowiki = checkUri(unstrip)
end
end
end
end
Linia 748: Linia 788:


-- translate some parameters
-- translate some parameters
result.chapterauthor, result.chapterComma = collectAuthors(result.chapterauthor)
local altAuthorParser = false
result.author, result.authorComma = collectAuthors(result.author)
if result.journal and result.pmid and result.author and not result.chapterauthor and not result.editor and not result.others then
altAuthorParser = true
end
result.chapterauthor = collectAuthors(result.chapterauthor, false)
result.author = collectAuthors(result.author, altAuthorParser)
result.lang = collectLanguages(result.lang)
result.lang = collectLanguages(result.lang)
result.editor, result.editorComma = collectAuthors(result.editor)
result.editor = collectAuthors(result.editor, false)
result.others, result.othersComma = collectAuthors(result.others)
result.others = collectAuthors(result.others, false)


local yearRange = false
-- parse main bibliographic date
if result.date and mw.ustring.match(result.date, "[12]%d%d%d[-–—][12]%d%d%d") then
yearRange = result.date
end
result.date, result.patchCitoidDate = parseDate(result.date or "", false, false, true)
if result.date then
if result.date then
result.year = tostring(result.date.year)
local bibDate = false
result.yearRange = yearRange
local bibDateHint = false
local coinsDate = false
local odnDate = false
for _, v in ipairs(resources.bibDates) do
for _, p in ipairs(v.patterns) do
local bib, c = mw.ustring.gsub(result.date, p, v.show)
if bib and (c > 0) then
bibDate = bib
bibDateHint = v.hint
if v.coins then
local cd, cc = mw.ustring.gsub(result.date, p, v.coins)
if cd and (cc > 0) then
coinsDate = cd
end
end
 
if v.odn then
local od, oc = mw.ustring.gsub(result.date, p, v.odn)
if od and (oc > 0) then
odnDate = od
end
end
break
end
if bibDate then
break
end
end
end
 
if bibDate then
result.date = { bib = bibDate, hint = bibDateHint, coins = coinsDate, odn = odnDate }
else
local date, patch = parseDate(result.date or "", false, false, true)
if date then
date.coins = (patch and date.year)
or (date.day and string.format("%04d-%02d-%02d", date.year, date.month, date.day))
or (date.month and string.format("%04d-%02d", date.year, date.month))
or date.year
date.odn = date.year
elseif result.date then
result.badDate = true
end
result.date = date
result.patchCitoidDate = patch
end
end
end


-- fix other dates
-- fix other dates
result.accessdate = parseDate(result.accessdate or "", false, false, false)
if result.accessdate then
if result.accessdate and not result.accessdate.day then
result.accessdate = parseDate(result.accessdate or "", false, false, false)
result.accessdate = nil
if result.accessdate and not result.accessdate.day then
result.badAccessDate = true
result.accessdate = nil
elseif not result.accessdate then
result.badAccessDate = true
end
end
end


Linia 782: Linia 875:
if url or result.titlelink then
if url or result.titlelink then
if result.url and (#result.url > 0) and (result.url ~= "{{{url}}}") then
if result.url and (#result.url > 0) and (result.url ~= "{{{url}}}") then
mw.logObject(result.url, "UNUSED URL")
result.urlWarning = true
result.urlWarning = true
end
end
Linia 793: Linia 885:
end
end
if result.journal then
if result.journal then
local journalAbbr, _ = mw.ustring.gsub(result.journal, "[%.%s]+", " ")
mw.logObject(journalAbbr, "journalAbbr")
if mw.ustring.match(journalAbbr, "^[%a%s]+[,:]?[%a%s]+%d?$") -- kandydat na skrót powinien mieć tylko litery z opcjonalnymi odstępami i co najwyżej jednym dwukropkiem lub przecinkiem
or mw.ustring.match(journalAbbr, "^[%a%s]+%([%a%s,]+%)$") then -- opcjonalnie jakieś dookreślenie w nawiasie
local expandedJournal = mw.loadData("Moduł:Cytuj/czasopisma")[mw.text.trim(journalAbbr)]
if expandedJournal then
result.originalJournal = result.journal
result.journal = expandedJournal
end
end
result.journal, result.journallink, result.journalurl = splitWikiLink(result.journal)
result.journal, result.journallink, result.journalurl = splitWikiLink(result.journal)
end
if result.journal and not result.journallink and not result.journalurl and not result.title and result.url then
result.journalurl = result.url
result.url = false
end
if result.url and isAutoGeneratedUrl(result.url) then
result.rejectedurl = true
result.url = false
end
if result.chapterurl and isAutoGeneratedUrl(result.chapterurl) then
result.rejectedurl = true
result.chapterurl = false
end
if result.journalurl and isAutoGeneratedUrl(result.journalurl) then
result.rejectedurl = true
result.journalurl = false
end
end


Linia 799: Linia 918:
local al, ad = detectArchive(result.url)
local al, ad = detectArchive(result.url)
if al then
if al then
result.archiveurl = true
result.archive = result.url
result.archive = result.url
result.url = al
result.url = al
if ad then result.archived = ad end
if ad then result.archived = ad end
end
end
elseif result.archive and (not result.url or not result.archived) then
elseif not result.archive and result.chapterurl then
local al, ad = detectArchive(result.chapterurl)
if al then
result.archivechapter = true
result.archive = result.chapterurl
result.chapterurl = al
if ad then result.archived = ad end
end
elseif not result.archive and result.journalurl then
local al, ad = detectArchive(result.journalurl)
if al then
result.archivejournal = true
result.archive = result.journalurl
result.journalurl = al
if ad then result.archived = ad end
end
elseif result.archive and not result.archived then
local al, ad = detectArchive(result.archive)
local al, ad = detectArchive(result.archive)
if al and not result.url then result.url = al end
if ad and not result.archived then result.archived = ad end
if ad and not result.archived then result.archived = ad end
end
if result.archive then
if result.chapterurl and not result.url then
result.archivechapter = true
elseif result.title then
result.archiveurl = true
elseif result.journal then
result.archivejournal = true
end
end
end


result.archived = parseDate(result.archived or "", false, false, false)
if result.archived then
if result.archived and not result.archived.day then
result.archived = parseDate(result.archived or "", false, false, false)
result.archived = null
if result.archived and not result.archived.day then
result.badArchivedDate = true
result.archived = null
elseif not result.archived then
result.badArchivedDate = true
end
end
end


if result.issue and result.journal then
if result.edition and result.journal and not result.volume and not result.issue then
local volume, issue = mw.ustring.match(result.issue, "^%s*([^%(]+)%s+%((.-)%)%s*$");
local volume, issue = mw.ustring.match(result.edition, "^%s*([^%(]+)%s+%((.-)%)%s*$");
if volume then
if volume then
result.journalvolume = volume
result.volume = volume
result.issue = issue
result.issue = issue
result.edition = nil
end
end
end
if result.pmc and (#result.pmc > 3) and (mw.ustring.sub(result.pmc, 1, 3) == "PMC") then
result.pmc = mw.ustring.sub(result.pmc, 4, #result.pmc)
end
if result.accessKind then
result.accessKind = access.choice[result.accessKind]
result.unknownAccess = not result.accessKind
else
result.accessKind = (result.pmc and "open")
or access.doi[doiPrefix]
or access.journals[result.journal]
end
if result.doi then
result.doi = mw.text.split(result.doi, '%s+', false)
for i, v in ipairs(result.doi) do
local doiPrefix
local doiSuffix
doiPrefix, doiSuffix = mw.ustring.match(v, "^10%.([^/]+)/(.+)$")
if (doiPrefix == "2307") and not result.jstor then
result.jstor = doiSuffix
end
if not result.accessKind and not result.unknownAccess then
result.accessKind = access.doi[doiPrefix]
end
end
end
if result.patent then
mw.logObject(result.patent,"input:patent")
local patentPatterns = mw.loadData("Moduł:Brudnopis/Paweł Ziemian/Cytuj/patent")
local patent = nil
for _, v in ipairs(patentPatterns) do
if string.match(result.patent, v.pattern) then
local patentNumber, _ = string.gsub(result.patent, v.pattern, v.number or "%1")
local patentCountry, _ = string.gsub(result.patent, v.pattern, v.country)
local patentInfo = v.info or patentPatterns.ccinfo[patentCountry]
if (result.url == nil) and v.url then
local url, _ = string.gsub(result.patent, v.pattern, v.url)
if checkUri(url) then
result.url = url
end
end
local patentTitle
if v.title then
patentTitle, _ = string.gsub(result.patent, v.pattern, v.title)
elseif patentInfo then
patentTitle =  string.format('<span title="%s">%s %s</span>', patentInfo, patentCountry, patentNumber)
else
patentTitle =  patentCountry.." "..patentNumber
end
patent = {
number = patentNumber,
application = v.application,
country = patentCountry,
title = patentTitle,
}
break
end
end
result.patent = patent
mw.logObject(result.patent,"parsed:patent")
end
end


Linia 837: Linia 1056:


data.diferentiator = mw.ustring.match(data.odn, "^([a-z])$") or false
data.diferentiator = mw.ustring.match(data.odn, "^([a-z])$") or false
if data.odn ~= "tak" and not data.diferentiator then
if data.odn ~= "tak" and not data.diferentiator then
-- TODO return only CITEREF...
-- TODO return only CITEREF...
Linia 850: Linia 1068:
return "CITEREF"
return "CITEREF"
.. (authors[1] and (authors[1].lastname or authors[1].exact) or "")
.. (authors.items[1] and (authors.items[1].lastname or authors.items[1].exact) or "")
.. (authors[2] and (authors[2].lastname or authors[2].exact) or "")
.. (authors.items[2] and (authors.items[2].lastname or authors.items[2].exact) or "")
.. (authors[3] and (authors[3].lastname or authors[3].exact) or "")
.. (authors.items[3] and (authors.items[3].lastname or authors.items[3].exact) or "")
.. (authors[4] and (authors[4].lastname or authors[4].exact) or "")
.. (authors.items[4] and (authors.items[4].lastname or authors.items[4].exact) or "")
.. (data.date and data.date.year or "")
.. (data.date and data.date.odn or "")
.. (data.diferentiator or "")
.. (data.diferentiator or "")
end
end
Linia 875: Linia 1093:
end
end
if authors then
if authors then
if authors[1].lastname then result["rft.aulast"] = authors[1].lastname end
if authors.items[1].lastname then result["rft.aulast"] = authors.items[1].lastname end
if authors[1].name then result["rft.aufirst"] = authors[1].name end
if authors.items[1].name then result["rft.aufirst"] = authors.items[1].name end
if authors[1].exact then result["rft.au"] = authors[1].exact end
if authors.items[1].exact then result["rft.au"] = authors.items[1].exact end
end
end
if data.date then
if data.date and data.date.coins then
result["rft.date"] = data.date.day and string.format("%04d-%02d-%02d", data.date.year, data.date.month, data.date.day)
result["rft.date"] = data.date.coins
or (data.date.month and string.format("%04d-%02d", data.date.year, data.date.month) or data.date.year)
end
end
if data.issue then result["rft.edition"] = data.issue end
if data.series then result["rft.series"] = data.series end
if data.edition then result["rft.edition"] = data.edition end
if data.publisher then result["rft.pub"] = data.publisher end
if data.publisher then result["rft.pub"] = data.publisher end
if data.place then result["rft.place"] = data.place end
if data.place then result["rft.place"] = data.place end
Linia 896: Linia 1114:


if data.oclc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:oclcnum/"..data.oclc})) end
if data.oclc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:oclcnum/"..data.oclc})) end
if data.doi then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..data.doi})) end
if data.doi then
for _, v in ipairs(data.doi) do
table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..v}))
end
end
if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
Linia 913: Linia 1135:
result["rft.jtitle"] = plainText(data.journal)
result["rft.jtitle"] = plainText(data.journal)
if data.chapter then result["rft.atitle"] = plainText(data.chapter) end
if data.chapter then result["rft.atitle"] = plainText(data.chapter) end
if data.date then
if data.date and data.date.coins then
result["rft.date"] = data.date.day and string.format("%04d-%02d-%02d", data.date.year, data.date.month, data.date.day)
result["rft.date"] = data.date.coins
or (data.date.month and string.format("%04d-%02d", data.date.year, data.date.month) or data.date.year)
end
end
if data.title and author then
if data.title and author then
Linia 922: Linia 1143:
if author[1].exact then result["rft.au"] = author[1].exact end
if author[1].exact then result["rft.au"] = author[1].exact end
end
end
if data.journalvolume then result["rft.volume"] = data.journalvolume end
if data.volume then result["rft.volume"] = data.volume end
if data.issue then result["rft.edition"] = data.issue end
if data.issue then result["rft.edition"] = data.issue end
if data.publisher then result["rft.pub"] = data.publisher end
if data.publisher then result["rft.pub"] = data.publisher end
Linia 936: Linia 1157:
if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
if data.pmc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmc/"..data.pmc})) end
if data.pmc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmc/"..data.pmc})) end
if data.doi then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..data.doi})) end
if data.doi then
for _, v in ipairs(data.doi) do
table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..v}))
end
end
if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
Linia 949: Linia 1174:
if data.title then result["rft.atitle"] = plainText(data.title) end
if data.title then result["rft.atitle"] = plainText(data.title) end
result["rft.jtitle"] = plainText(data.published)
result["rft.jtitle"] = plainText(data.published)
if data.date then
if data.date and data.date.coins then
result["rft.date"] = data.date.day and string.format("%04d-%02d-%02d", data.date.year, data.date.month, data.date.day)
result["rft.date"] = data.date.coins
or (data.date.month and string.format("%04d-%02d", data.date.year, data.date.month) or data.date.year)
end
end
if data.title and author then
if data.title and author then
Linia 968: Linia 1192:
return coinsData;
return coinsData;
end
end
local function patentCOinS(data)
local result = {}
result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal"
if data.title then result["rft.title"] = plainText(data.title) end
result[data.patent.application and "rft.applnumber" or "rft.number"] = data.patent.number
result["rft.cc"] = data.patent.country
if data.date and data.date.coins then
result[data.patent.application and "rft.appldate" or "rft.date"] = data.date.coins
end
if author then
if author[1].lastname then result["rft.aulast"] = author[1].lastname end
if author[1].name then result["rft.aufirst"] = author[1].name end
if author[1].exact then result["rft.au"] = author[1].exact end
end
-- rft.assignee = author (wszyscy?)
-- rft.inventor = others (wszyscy?)
local params = {
"ctx_ver=Z39.88-2004",
mw.uri.buildQueryString(result),
}
if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
local coinsData = table.concat(params, "&")
return coinsData;
end


local function COinS(data, coinsFormat)
local function COinS(data, coinsFormat)
if (coinsFormat == "info:ofi/fmt:kev:mtx:book") and data.title and (#data.title > 0) then
if resources.abbrTitles[data.title] then
-- full citation is elsewhere
return false
elseif (coinsFormat == "info:ofi/fmt:kev:mtx:book") and data.title and (#data.title > 0) then
-- title is mandatory element for books
-- title is mandatory element for books
return bookCOinS(data)
return bookCOinS(data)
Linia 978: Linia 1233:
elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.published and (#data.published > 0) then
elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.published and (#data.published > 0) then
return webCOinS(data)
return webCOinS(data)
elseif coinsFormat == "info:ofi/fmt:kev:mtx:patent" and data.patent then
return patentCOinS(data)
elseif data.title and (#data.title > 0) then
elseif data.title and (#data.title > 0) then
-- treat web or unrecognized citations as book
-- treat web or unrecognized citations as book
Linia 986: Linia 1243:
end
end


local function Cite(p, mode)
local function Cite(p, mode, appendText)
-- debug helper
-- debug helper
if p.args[3] then mw.log(p.args[3]) end
if p.args[3] then mw.log(p.args[3]) end
local customMode = mode


-- try to determine type basing on passed parameters
-- try to determine type basing on passed parameters
Linia 1006: Linia 1264:
end
end


local builder = mw.html.create("span")
local builder = mw.html.create("cite")
builder
builder
:addClass("citation")
:addClass("citation")
:addClass(resources.cite[mode] or nil)
:addClass(access.class[data.accessKind])
:attr("id", prepareOdnIdentifier(data))
:attr("id", prepareOdnIdentifier(data))
--:wikitext(access.render[data.accessKind], ' ')


local needDot = false
local needDot = false
local nextAuthorGroup = false
local nextAuthorGroup = false
if data.title then
if data.title or data.patent then
if data.chapter then
if data.chapter then
local authors = data.editor and data.author or data.chapterauthor
local authors = data.editor and data.author or data.chapterauthor
if authors then
if authors then
builder:wikitext(formatAuthors(authors, false, nextAuthorGroup), ", ")
local list, etal = formatAuthors(authors, false, nextAuthorGroup, nil)
builder:wikitext(list, ", ")
nextAuthorGroup = true
nextAuthorGroup = true
end
end
Linia 1024: Linia 1286:
local title = softNoWiki(data.chapter)
local title = softNoWiki(data.chapter)
if data.chapterurl then
if data.chapterurl then
builder:wikitext("[", escapeUrl((not data.url and data.archive) and data.archive or data.chapterurl), " ''", title, "'']")
builder:wikitext("[", escapeUrl(data.archivechapter and data.archive or data.chapterurl), " ''", title, "'']")
elseif data.chapterlink then
elseif data.chapterlink then
builder:wikitext("[[", data.chapterlink, "|''", title, "'']]")
builder:wikitext("[[", data.chapterlink, "|''", title, "'']]")
Linia 1031: Linia 1293:
end
end
if not mw.ustring.match(plainText(data.chapter), ",$") then
if data.format then
builder:wikitext(",")
builder:wikitext(" &#x5B;", data.format, "&#x5D;")
end
end


builder:wikitext(" [w:] ")
builder:wikitext(", [w:] ")
end
end


Linia 1047: Linia 1309:
end
end
if authors then
if authors then
builder:wikitext(formatAuthors(authors, not (editor or false), nextAuthorGroup))
local list, etal = formatAuthors(authors, not (editor or false), nextAuthorGroup, editor and " i inni red." or nil)
builder:wikitext(list)
nextAuthorGroup = true
nextAuthorGroup = true
if editor then
if editor and not etal and not authors.etal then
builder:wikitext(" (red.)")
builder:wikitext(" (red.)")
end
end
builder:wikitext(", ")
builder:wikitext(", ")
end
end
if customMode and data.authorextra then
builder:wikitext(data.authorextra, ", ")
end
if resources.abbrTitles[data.title] then
local title = resources.abbrTitles[data.title]
builder:wikitext(title)
needDot = not mw.ustring.match(title, "%.%]%]$")
and not mw.ustring.match(title, "%.$")
elseif data.title then
local title = softNoWiki(data.title)
if data.url or data.archiveurl then
builder:wikitext("[", escapeUrl(data.archiveurl and data.archive or data.url), " ''", title, "'']")
elseif data.titlelink then
builder:wikitext("[[", data.titlelink, "|''", title, "'']]")
else
builder:wikitext("''", title, "''")
end
if not data.chapter and data.format then
builder:wikitext(" &#x5B;", data.format, "&#x5D;")
needDot = true
elseif not mw.ustring.match(plainText(title), "[%.,!?]$") then
needDot = true
end
local title = softNoWiki(data.title)
local showmediatype = data.mediatype and (#data.mediatype > 0)
if data.url then
if showmediatype then
builder:wikitext("[", escapeUrl(data.archive or data.url), " ''", title, "'']")
builder:wikitext(" &#x5B;", data.mediatype, "&#x5D;")
elseif data.titlelink then
needDot = true
builder:wikitext("[[", data.titlelink, "|''", title, "'']]")
end
else
builder:wikitext("''", title, "''")
end
end
if not mw.ustring.match(plainText(title), "%p$") then
 
if not editor and data.editor then
local list, etal = formatAuthors(data.editor, false, true, " i inni red.")
builder:wikitext(needDot and ", " or " ", list, (etal or data.editor.etal) and "" or " (red.)")
needDot = true
needDot = true
end
end
 
local showmediatype = data.mediatype and (#data.mediatype > 0)
if data.others then
if showmediatype then
local list, etal = formatAuthors(data.others, true, true, nil)
builder:wikitext(" &#x5B;", data.mediatype, "&#x5D;")
builder:wikitext(needDot and ", " or " ", data.patent and resources.patent.inventor.." " or "", list)
needDot = true
needDot = true
end
end


if not editor and data.editor then
if data.patent then
builder:wikitext(", ", formatAuthors(data.editor, false, true), " (red.)")
local title = (not data.title and data.url) and string.format("[%s %s]", escapeUrl(data.url), data.patent.title) or data.patent.title
end
builder:wikitext(needDot and ", " or " ", resources.patent[data.patent.application], " ", title)
if data.others then
builder:wikitext(", ", formatAuthors(data.others, true, true))
needDot = true
needDot = true
end
end
elseif data.journal and data.author then
local list, etal = formatAuthors(data.author, false, false, nil)
builder:wikitext(list, ", ")
end
end
 
if data.work then
if data.work then
builder:wikitext(", [w:] ", data.work, (not data.mediatype and data.url) and " [online]" or "")
builder:wikitext((data.title or data.patent) and ", " or "", "[w:] ", data.work, (not data.mediatype and data.url) and " [online]" or "")
needDot = true
needDot = true
end
end


if data.journal and (not data.published or (data.journal ~= data.published)) then
if data.journal and (not data.published or (data.journal ~= data.published)) then
--builder:wikitext((data.title or data.work) and ", [w:] „" or "„")
builder:wikitext((data.title or data.work) and ", " or "")
builder:wikitext((data.title or data.work) and ", „" or "")
local title = softNoWiki(data.journal)
local title = softNoWiki(data.journal)
if data.journalurl then
if data.journalurl or data.archivejournal then
builder:wikitext("[", escapeUrl(data.journalurl), " ", title, "]")
builder:wikitext("[", escapeUrl(data.archivejournal and data.archive or data.journalurl), " ", title, "]")
elseif data.journallink then
elseif data.journallink then
builder:wikitext("[[", data.journallink, "|", title, "]]")
builder:wikitext("[[", data.journallink, "|", title, "]]")
else
else
builder:wikitext(title)
builder:wikitext("„", title, "”")
end
end
builder:wikitext("”")
needDot = true
needDot = true
end
end
Linia 1108: Linia 1394:
end
end


if data.issue then
if data.edition then
if data.journalvolume then
builder:wikitext(data.journal and ", " or ", wyd. ", data.edition)
builder:wikitext(", ", data.journalvolume, " (", data.issue, ")")
needDot = true
elseif data.journal then
end
builder:wikitext(", ", data.issue)
else
if data.volume then
builder:wikitext(", wyd. ", data.issue)
builder:wikitext(data.journal and ", " or ", t. ", data.volume)
end
needDot = true
end
if data.journal and data.issue then
builder:wikitext(" (", data.issue, ")")
needDot = true
needDot = true
end
end
Linia 1141: Linia 1431:
end
end
if data.date then
if data.date then
if data.yearRange then
local shortDate = data.journal and (data.doi or data.pmid or data.pmc)
builder:wikitext(place and " " or ", ", data.yearRange)
if data.date.bib and data.date.hint then
builder:wikitext(place and " " or ", "):tag("span"):attr("title", data.date.hint):wikitext(data.date.bib)
elseif data.date.bib  then
builder:wikitext(place and " " or ", ", data.date.bib)
elseif data.date.day and shortDate then
builder:wikitext(place and " " or ", "):tag("span"):attr("title", tostring(data.date.day).." "..resources.months[data.date.month].d.." "..tostring(data.date.year)):wikitext(data.date.year)
elseif data.date.month and shortDate then
builder:wikitext(place and " " or ", "):tag("span"):attr("title", resources.months[data.date.month].m.." "..tostring(data.date.year)):wikitext(data.date.year)
elseif data.date.day then
elseif data.date.day then
builder:wikitext(", ", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year))
builder:wikitext(", ", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year))
Linia 1148: Linia 1445:
builder:wikitext(", ", resources.months[data.date.month].m, " ", tostring(data.date.year))
builder:wikitext(", ", resources.months[data.date.month].m, " ", tostring(data.date.year))
else
else
builder:wikitext(place and " " or ", ", data.year)
builder:wikitext(place and " " or ", ", data.date.year)
end
end
builder:wikitext(data.diferentiator or "")
builder:wikitext(data.diferentiator or "")
Linia 1154: Linia 1451:
end
end


if not data.journal and (data.series or data.issue) then
builder:wikitext(" (", data.series or "", (data.series and data.issue) and "; " or "", data.issue or "", ")")
needDot = true
elseif data.journal and data.series then
builder:wikitext(" (", data.series, ")")
needDot = true
end
if data.p and #data.p > 0 then
if data.p and #data.p > 0 then
local isNonStandardPageNumber = mw.ustring.match(data.p, "[^%s0-9,%-–]")
local isNonStandardPageNumber = mw.ustring.match(data.p, "[^%s0-9,%-–]")
Linia 1161: Linia 1466:
if data.doi then
if data.doi then
builder:wikitext(", [[DOI (identyfikator cyfrowy)|DOI]]:&nbsp;[http://dx.doi.org/", data.doi, " ", data.doi, "]")
local separator = "&nbsp;"
builder:addClass("doi"):wikitext(", [[DOI (identyfikator cyfrowy)|DOI]]:")
local doiLink = first(resources.params.doi.link)
for _, v in ipairs(data.doi) do
builder:wikitext(separator, "[", doiLink, mw.uri.encode(v), " ", softNoWiki(v), "]")
separator = ", "
end
needDot = true
needDot = true
end
end
Linia 1167: Linia 1478:
if data.isbn then
if data.isbn then
for i,v in ipairs(data.isbn) do
for i,v in ipairs(data.isbn) do
builder:wikitext(", ISBN ", v)
builder:wikitext(", ")
require("Moduł:ISBN").link(builder, v)
end
end
needDot = true
needDot = true
end
end


if data.lccn then
if data.lccn then
builder:wikitext(", [[Biblioteka Kongresu Stanów Zjednoczonych|LCCN]] [http://lccn.loc.gov/", mw.uri.encode(data.lccn), " ", data.lccn, "]")
builder:wikitext(", [[Biblioteka Kongresu|LCCN]] [", first(resources.params.lccn.link), mw.uri.encode(data.lccn), " ", data.lccn, "]")
needDot = true
needDot = true
end
end
if data.issn then
if data.issn then
builder:wikitext(", [[International Standard Serial Number|ISSN]] [http://worldcat.org/issn/", data.issn, " ", data.issn, "]")
builder:tag("span"):addClass("issn"):wikitext(", [[International Standard Serial Number|ISSN]] [", first(resources.params.issn.link), data.issn, " ", data.issn, "]")
needDot = true
needDot = true
end
end
if data.pmid then
if data.pmid then
builder:wikitext(", [[PMID]]:&nbsp;[http://www.ncbi.nlm.nih.gov/pubmed/", data.pmid, " ", data.pmid, "]")
builder:addClass("pmid"):wikitext(", [[PMID]]:&nbsp;[", first(resources.params.pmid.link), data.pmid, " ", data.pmid, "]")
needDot = true
needDot = true
end
end
if data.pmc then
if data.pmc then
builder:wikitext(", [[PMCID]]:&nbsp;[http://www.ncbi.nlm.nih.gov/pmc/articles/PMC", data.pmc, "/ PMC", data.pmc, "]")
builder:addClass("pmc"):wikitext(", [[PMCID]]:&nbsp;[", first(resources.params.pmc.link), data.pmc, "/ PMC", data.pmc, "]")
needDot = true
needDot = true
end
end
if data.bibcode then
if data.bibcode then
builder:wikitext(", [[Bibcode]]:&nbsp;[http://adsabs.harvard.edu/abs/", data.bibcode, " ", data.bibcode, "]")
builder:wikitext(", [[Bibcode]]:&nbsp;[", first(resources.params.bibcode.link), data.bibcode, " ", data.bibcode, "]")
needDot = true
needDot = true
end
end
if data.oclc then
if data.oclc then
builder:wikitext(", [[Online Computer Library Center|OCLC]]&nbsp;[http://worldcat.org/oclc/", mw.uri.encode(data.oclc), " ", data.oclc, "]")
builder:wikitext(", [[Online Computer Library Center|OCLC]]&nbsp;[", first(resources.params.oclc.link), mw.uri.encode(data.oclc), " ", data.oclc, "]")
needDot = true
needDot = true
end
end
Linia 1206: Linia 1519:
local eprint, class = mw.ustring.match(data.arxiv, "^(%S+)%s+%[([^%[%]]+)%]$")
local eprint, class = mw.ustring.match(data.arxiv, "^(%S+)%s+%[([^%[%]]+)%]$")
if eprint then
if eprint then
builder:wikitext("[//arxiv.org/abs/", eprint, " ", eprint, "] &#x5B;[//arxiv.org/archive/", class, " ", class, "]&#x5D;" )
builder:wikitext("[", first(resources.params.arxiv.link), eprint, " ", eprint, "] &#x5B;[//arxiv.org/archive/", class, " ", class, "]&#x5D;" )
else
else
builder:wikitext("[//arxiv.org/abs/", data.arxiv, " ", data.arxiv, "]" )
builder:wikitext("[", first(resources.params.arxiv.link), data.arxiv, " ", data.arxiv, "]" )
end
end
needDot = true
end
if data.jstor then
builder:tag("span"):addClass("jstor"):wikitext(", [[JSTOR]]:&nbsp;[", first(resources.params.jstor.link), data.jstor, " ", data.jstor, "]")
needDot = true
end
if data.ol then
builder:tag("span"):addClass("open-library"):wikitext(", [[Open Library|OL]]:&nbsp;[", first(resources.params.ol.link), data.ol, " ", data.ol, "]")
needDot = true
needDot = true
end
end
Linia 1219: Linia 1542:
if data.accessdate then
if data.accessdate then
builder:wikitext(" [dostęp ", string.format("%04d-%02d-%02d", data.accessdate.year, data.accessdate.month, data.accessdate.day), "]")
builder:tag("span"):addClass("accessdate"):wikitext(" [dostęp ", string.format("%04d-%02d-%02d", data.accessdate.year, data.accessdate.month, data.accessdate.day), "]")
needDot = true
needDot = true
end
end
if data.url and data.archive then
if data.archive then
builder:wikitext(" [zarchiwizowane z [", escapeUrl(data.url), " adresu]")
builder:wikitext(" [zarchiwizowane")
local url = data.archiveurl and data.url or (data.archivechapter and data.chapterurl or data.journalurl)
if url then
builder:wikitext(" z [", escapeUrl(url), " adresu]")
end
if data.archived and data.archived.day then
if data.archived and data.archived.day then
builder:wikitext(" ", string.format("%04d-%02d-%02d", data.archived.year, data.archived.month, data.archived.day))
builder:wikitext(" ", string.format("%04d-%02d-%02d", data.archived.year, data.archived.month, data.archived.day))
Linia 1246: Linia 1573:
builder:wikitext(" ", languages)
builder:wikitext(" ", languages)
needDot = true
needDot = true
end
if data.fullStop then
if not mw.ustring.match(data.fullStop, "^[%.!?,;:]") then
builder:wikitext(", ")
end
builder:wikitext(data.fullStop)
needDot = mw.ustring.match(data.fullStop, "[%.!?,;:]$") == nil
end
end


Linia 1252: Linia 1587:
end
end


if appendText then
builder:wikitext(appendText)
end
-- categories
-- categories
local addCategories = mw.title.getCurrentTitle().namespace == 0
local addCategories = mw.title.getCurrentTitle().namespace == 0
local problems = {}
local problems = {}
if mode == 1 then
if not customMode and (mode == 1) then
builder:wikitext(resources.categories.undetermined)
builder:wikitext(resources.categories.undetermined)
table.insert(problems, "???")
table.insert(problems, "???")
Linia 1270: Linia 1609:
table.insert(problems, resources.categories.sameJournalAndPublished)
table.insert(problems, resources.categories.sameJournalAndPublished)
end
end
end
if (not data.url and not data.chapterurl) or (not data.title and not data.journalurl) then
builder:addClass(data.urlnowiki and "urlnowiki" or "nourl")
end
end
Linia 1278: Linia 1621:
table.insert(problems, data.missing)
table.insert(problems, data.missing)
missing = true
missing = true
elseif needurl and not data.url and not data.chapterurl and not data.arxiv then
elseif needurl and not data.url and not data.chapterurl and not data.arxiv and not data.archive then
-- build in support for missing external link for page citation
-- build in support for missing external link for page citation
table.insert(problems, resources.params.url.name)
table.insert(problems, resources.params.url.name)
Linia 1296: Linia 1639:
builder:wikitext(string.format(resources.categories.missingArg, resources.modes[mode]))
builder:wikitext(string.format(resources.categories.missingArg, resources.modes[mode]))
end
end
if data.chapterComma or data.authorComma or data.editorComma or data.othersComma or data.othersbookvolumeComma then
if (data.chapterauthor and data.chapterauthor.comma)
or (data.author and (data.author.comma == true))
or (data.editor and data.editor.comma)
or (data.others and data.others.comma) then
table.insert(problems, "!!!")
if addCategories then
if addCategories then
builder:wikitext(resources.categories.suspectedComma)
builder:wikitext(resources.categories.suspectedComma)
end
end
end
table.insert(problems, "!!!")
if data.author and (data.author.comma == "alt") then
table.insert(problems, "a?")
if addCategories then
builder:wikitext(resources.categories.altAuthor)
end
end
if data.originalJournal then
table.insert(problems, "c?")
if addCategories then
builder:wikitext(resources.categories.altJournal)
end
end
local citewiki = (data.journal and mw.ustring.match(data.journal, "[Ww]ikipedia"))
or (data.publisher and mw.ustring.match(data.publisher, "[Ww]ikipedia"))
or (data.published and mw.ustring.match(data.published, "[Ww]ikipedia"))
or (data.url and mw.ustring.match(data.url, "%.wikipedia%.org"))
if citewiki then
table.insert(problems, "wiki?")
if addCategories then
builder:wikitext(resources.categories.wiki)
end
end
if data.unknownAccess then
table.insert(problems, "dostęp?")
if addCategories then
builder:wikitext(resources.categories.unknownAccess)
end
end
if data.rejectedurl then
table.insert(problems, "<s>url</s>")
if addCategories then
builder:wikitext(resources.categories.rejectedUrl)
end
end
end
if data.urlWarning then
if data.urlWarning then
table.insert(problems, "Url")
if addCategories then
if addCategories then
builder:wikitext(resources.categories.unusedUrl)
builder:wikitext(resources.categories.unusedUrl)
end
end
table.insert(problems, "Url")
end
end
if data.patchCitoidDate then
if data.patchCitoidDate then
table.insert(problems, "1 stycznia")
table.insert(problems, "1 stycznia")
end
if data.badDate then
table.insert(problems, "data?")
end
if data.badAccessDate then
table.insert(problems, "data dostępu?")
end
if data.badArchivedDate then
table.insert(problems, "zarchiwizowano?")
end
if addCategories and (data.badDate or data.badAccessDate or data.badArchiveDate) then
builder:wikitext(resources.categories.badDate)
end
if (data.author and data.author.etal)
or (data.chapterauthor and data.chapterauthor.etal)
or (data.editor and data.editor.etal)
or (data.others and data.others.etal) then
table.insert(problems, "i inni")
if addCategories then
builder:wikitext(resources.categories.etal)
end
end
end


if #problems > 0 then
if #problems > 0 then
local info = builder:tag("span"):addClass("problemy-w-cytuj")
local info = builder:tag("span")
if addCategories then
:addClass("problemy")
info:css("display","none")
:addClass("problemy-w-cytuj")
else
:attr("aria-hidden", "true")
info:css("color", "red")
:attr("data-nosnippet", "")
end
info:wikitext(table.concat(problems,", "))
info:wikitext(table.concat(problems,", "))
end
end
Linia 1328: Linia 1725:
end
end


local module = {}
return {
auto = function(frame)
return Cite(frame:getParent(), nil, nil)
end,
 
custom = function(frame)
local traceCategory = false
local pagename = mw.title.getCurrentTitle()
if (pagename.namespace == 10) and frame.getParent then
local template = mw.title.new( frame:getParent():getTitle(), "Szablon" )
if mw.title.compare(template, pagename) == 0 then
traceCategory = resources.categories.traceInvokeCustom
end
end
local customMode = frame.args[1]
local mode = 1
if customMode then
customMode = mw.text.trim(customMode)
for i, v in ipairs(resources.modes) do
if customMode == v then
mode = i
break
end
end
end


module.auto = function(frame)
return Cite(frame, mode, traceCategory)
return Cite(frame:getParent(), nil)
end,
end


return module
}

Aktualna wersja na dzień 11:14, 8 kwi 2022

Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:Cytuj/opis

local resources = mw.loadData("Moduł:Cytuj/dane")
local access = mw.loadData("Moduł:Cytuj/dostęp")

local function checkUri(uri)
	local urilen = #uri
	for _,v in ipairs(resources.supportedUriSchemas) do
		if (#v < urilen) and (string.lower(string.sub(uri,1, #v)) == v) then
			return not string.match(uri, '%s')
		end
	end
end

local function softNoWiki(text)
	local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = "&#x22;", ["'"] = "&#x27;", ["["] = "&#x5B;", ["]"] = "&#x5D;", ["{"] = "&#x7B;", ["|"] = "&#x7C;", ["}"] = "&#x7D;"})
	-- przywróc [[szablon:J]] z kursywą tak/nie
	result, count = string.gsub(result, "<span +style=&#x22;font%-style: ?([a-z]+);?&#x22; +lang=&#x22;([a-z%-]+)&#x22; *>", "<span style=\"font-style: %1;\" lang=\"%2\">")
	-- przywróc [[szablon:J]] goły
	result, count = string.gsub(result, "<span +lang=&#x22;([a-z%-]+)&#x22; *>", "<span lang=\"%1\">")
	-- przywróć nowiki
	result, count = string.gsub(result, "\127&#x27;&#x22;`UNIQ%-%-(nowiki%-[0-9A-F]+)%-QINU`&#x22;&#x27;\127", "\127'\"`UNIQ--%1-QINU`\"'\127")
	return result
end

local function escapeUrl(url)
	local result, count = string.gsub(url, "[ '%[%]]", { [" "] = "%20", ["'"] = "%27", ["["] = "%5B", ["]"] = "%5D"})
	return result
end

local function plainText(text)
	local result, count = string.gsub(text, "</?[Ss][Pp][Aa][Nn][^>]*>", "")
	return result
end

local function first(data)
	return type(data) == "table" and data[1] or data
end

local function determineMode(p)
	local detector = {}
	local count = 0
	for i, v in ipairs(resources.modes) do
		detector[i] = v
		count = count + 1
	end
	
	detector[1] = false -- skip 'auto'
	count = count - 1
	for k, v in pairs(resources.params) do
		local arg = p.args[v.name]
		for i, w in ipairs(v.used) do
			if not w and arg then
				-- unexpected argument
				if detector[i] then
					detector[i] = false
					count = count - 1
					if count == 0 then
						-- the mode cannot be determined
						break
					end
				end
			end
		end
		if count == 0 then
			-- the mode cannot be determined
			break
		end
	end
	
	if count == 1 then
		for i, v in ipairs(detector) do
			if detector[i] then
				return i, resources.COinS[i]
			end
		end
	end
	
	if detector[4] -- web?
	and p.args[resources.params.url.name]
	then
		-- promote to web but without COinS
		return 4, false
	end
	
	for i, v in ipairs(detector) do
		if detector[i] then
			-- if type is determined more than once
			-- use only the first one without COinS
			return i, false
		end
	end

	-- in case nothing is selected
	-- use the auto mode as default fallback
	return 1
end

local authorMetatable = {}
local authorMethodtable = {}

authorMetatable.__index = authorMethodtable

local function checkPatterns(author, prefixes, suffixes)
	if author.exact then
		return false
	end
	
	if author.prefix and prefixes then
		for _, v in ipairs(prefixes) do
			if mw.ustring.match(author.prefix, v) then
				return true
			end
		end
	end
	
	if author.suffix and suffixes then
		for _, v in ipairs(suffixes) do
			if mw.ustring.match(author.suffix, v) then
				return true
			end
		end
	end

	return false
end

authorMethodtable.format = function(data, namefirst)
	if data.exact then
		return data.exact
	end

	if namefirst and data.familynamefirst then
		namefirst = false
	end
	
	local builder = mw.html.create()
	local name = data.name and (#data.name > 0)
	local initials = data.nameinitials and (#data.nameinitials > 0)
	local namehint = nil
	if name and initials and (data.name ~= data.nameinitials) then
		namehint = data.name
	end
	
	if not data.familynamefirst and (name or initials) then
		local before = namefirst and builder or builder:tag("span"):addClass("cite-name-before")
		if name then
			before:tag("span"):addClass("cite-name-full"):wikitext(softNoWiki(data.name))
		end
		if initials then
			before:tag("span"):css("display", "none"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
		end
		before:wikitext("&nbsp;")
	end

	builder:tag("span"):addClass("cite-lastname"):wikitext(softNoWiki(data.lastname))

	if not namefirst and (name or initials) then
		local after = data.familynamefirst and builder or builder:tag("span"):css("display", "none"):addClass("cite-name-after")
		after:wikitext("&nbsp;")
		if name then
			after:tag("span"):addClass("cite-name-full"):wikitext(softNoWiki(data.name))
		end
		if initials then
			after:tag("span"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
		end
		if data.js then
			after:wikitext(",")
		end
	end
	
	if data.js then
		builder:wikitext("&nbsp;", data.js)
	end
	
	return tostring(builder)
end

authorMethodtable.towiki = function(data)
	if data.exact then
		return data.exact
	end

	local result = {}
	local name = data.name and (#data.name > 0)
	if not data.familynamefirst and name then
		table.insert(result,softNoWiki(data.name))
		table.insert(result, " ")
	end
	
	table.insert(result, softNoWiki(data.lastname))

	if data.familynamefirst and name then
		table.insert(result, " ")
		table.insert(result, softNoWiki(data.name))
	end

	return table.concat(result)
end

local function makeInitials(name)
	local nameinitials = mw.ustring.gsub(name, "(%w[Hh]?)[%w]*%.?([%s%-–—]?)%s*", "%1. ") -- zostaw początki słów (jedna litera + opcjonalne następujące 'h')
	nameinitials = mw.ustring.gsub(nameinitials, "%f[%w]%l%.%s", "")               -- usuń inicjały z małych liter
	nameinitials = mw.ustring.gsub(nameinitials, "([^C%W])[Hh]%.?%s", "%1. ")      -- usuń drugie 'h' jeśli nie zaczyna się na 'C'
	nameinitials = mw.ustring.gsub(nameinitials, "(%u[Hh]?)[%.%s]*", "%1.")        -- dodaj brakujące kropki i usuń zbędne spacje
	return mw.text.trim(nameinitials)
end

local function fixInitials(name)
	local result, _ = mw.ustring.gsub(name, "^(%uh?)%.?%s+(%uh?)%.", "%1.%2.") -- popraw inicjały na początku
	result, _ = mw.ustring.gsub(result, "%f[%a](%uh?)%.%s+(%uh?)%.", "%1.%2.") -- popraw inicjały w środku
	result, _ = mw.ustring.gsub(result, "%f[%a](%uh?)%.%s+(%uh?)%.", "%1.%2.") -- popraw kolejne inicjały w środku
	return result
end

local function isInQuotes(text)
	if (string.len(text) < 2) then
		return false;
	end
	local tstart = text:sub(1, 1);
	if (tstart ~= '"') then
		return false;
	end
	local tend = text:sub(-1);
	if (tend ~= '"') then
		return false;
	end
	return true;  
end

local function parseAuthor(author)
	
	local result = {}
	
	if string.match(author, "\127") then -- wpisy z <nowiki> nie są analizowane
		result.exact = author
		setmetatable(result, authorMetatable)
		return result
	end
	
	local author = mw.text.trim(author)
	
	local a = string.gsub(author, "\\[\\%.:]", { ["\\\\"]="\\", ["\\."]=",", ["\\:"]=";", })
	if a ~= author then
		result.exact = a
		setmetatable(result, authorMetatable)
		return result
	end

	if resources.exactAuthors[author] then
		result.exact = author
		setmetatable(result, authorMetatable)
		return result
	end

	local exactName = mw.ustring.match(author, "^%s*%*%s*(.*)$")
	if exactName then
		result.exact = mw.text.trim(exactName)
		if #result.exact == 0 then
			return nil
		end
		
		setmetatable(result, authorMetatable)
		return result
	end

	local prefix0, link, description, suffix0 = mw.ustring.match(author, "^(.-)%[%[(.-)%|(.-)%]%](.*)$")
	if prefix0 then
		result.link = link
		author = description
	else
		prefix0, link, suffix0 = mw.ustring.match(author, "^(.-)%[%[(.-)%]%](.*)$")
		if prefix0 then
			author = link
			result.link = link
		else
			prefix0 = ""
			suffix0 = ""
		end
	end

	local prefix1, rest = mw.ustring.match(author, "^([%l%p%s]+)(.+)$")
	if not prefix1 then
		rest = author
		prefix1 = ""
	end

	local prefix = mw.text.trim(prefix0.." "..prefix1)
	if #prefix > 0 then
		if mw.ustring.sub(prefix, -1) == "#" then
			result.familynamefirst = true
			prefix = mw.text.trim(mw.ustring.match(prefix, "^(.-)#$"))
		end
		if #prefix > 0 then
			result.prefix = mw.ustring.gsub(prefix, "%s+", " ") -- collapse spaces
		end
	end

	local rest2, suffix = mw.ustring.match(rest, "^([%w%-%.%s]-)%s([%l%p%s]-)$")
	if not suffix then
		rest2 = rest
		suffix = ""
	end
	
	suffix = mw.text.trim(suffix.." "..suffix0)
	if #suffix > 0 then
		result.suffix = mw.ustring.gsub(suffix, "%s+", " ") -- collapse spaces
		suffix = " "..result.suffix
		for i, v in ipairs(resources.js) do
			if mw.ustring.match(suffix, v[1]) then
				result.suffix = mw.text.trim(mw.ustring.gsub(suffix, v[1], ""))
				result.js = v[2]
				break
			end
		end
	else
		for i, v in ipairs(resources.js) do
			if mw.ustring.match(rest2, v[1]) then
				rest2 = mw.text.trim(mw.ustring.gsub(rest2, v[1], ""))
				result.js = v[2]
				break
			end
		end
	end

	local lastname, name = mw.ustring.match(rest2, "%s*([^,]-)%s*,%s*(.-)%s*$")
	if not lastname then
		if result.familynamefirst then
			lastname, name = mw.ustring.match(rest2, "%s*(%u[%l%d%p]*)%s+(.-)%s*$")
		else
			local prefix2
			name, lastname, prefix2 = mw.ustring.match(rest2, "%s*(.-)%s+((%l[%l%p]%l?)%u[%w%p]-)%s*$")
			if not resources.lastnamePrefixes[prefix2] then
				name, lastname = mw.ustring.match(rest2, "%s*(.-)%s+(%u[%w%p]-)%s*$")
			end
		end
	elseif resources.lastnamePrefixes[prefix1] then
		lastname = prefix1 .. lastname
	elseif resources.lastnamePrefixes[prefix1] == false then
		name = name.." "..mw.text.trim(prefix1)
	end
	
	if not lastname then
		result.lastname = mw.text.trim(rest2)
	else
		result.name = fixInitials(name)
		result.lastname = lastname
		result.nameinitials = makeInitials(name)
	end
	
	if #result.lastname == 0 then
		return nil
	end
	
	setmetatable(result, authorMetatable)
	return result
end

local function parseDate(date, month, year, patch)
	local result = {}
	
	-- parse full date
	local y, m, d = false, false, false
	y, m, d = mw.ustring.match(date, "(%d%d%d%d)[%-%s%./](%d%d?)[%-%s%./](%d%d?)")
	
	if y and patch and (date == (y.."-01-01")) then
		result.year = tonumber(y)
		result.month = false
		result.day = false
		return result, true
	end
	
	if not y then
		d, m, y = mw.ustring.match(date, "(%d%d?)[%-%s%.](%d%d?)[%-%s%.](%d%d%d%d)")
		if not y then
			y, m, d = mw.ustring.match(date, "(%d%d%d%d)%s*(%w+)%s*(%d%d?)")
			if not y then
				d, m, y = mw.ustring.match(date, "(%d%d?)%s*(%w+)%s*(%d%d%d%d)")
			end
			if m then
				m = resources.monthparser[mw.ustring.lower(m)]
				if not m then
					y = false
					m = false
					d = false
				end
			end
		end
	end

	if y then
		y = tonumber(y)
		m = tonumber(m)
		d = tonumber(d)
	end
	if y and ((d > 31) or (m > 12) or (d < 1) or (m < 1)) then 
		y = false
		m = false
		d = false
	elseif y then
		result.year = y
		result.month = m
		result.day = d
		return result, false
	end
	
	-- parse year and month
	y, m = mw.ustring.match(date, "(%d%d%d%d)[%-%s%./](%d%d?)")
	if not y then
		m, y = mw.ustring.match(date, "(%d%d?)[%-%s%./](%d%d%d%d)")
		if not y then
			y, m = mw.ustring.match(date, "(%d%d%d%d)%s*(%w+)")
			if not y then
				m, y = mw.ustring.match(date, "(%w+)%s*(%d%d%d%d)")
			end
			if m then
				m = resources.monthparser[mw.ustring.lower(m)]
				if not m then
					y = false
					m = false
				end
			end
		end
	end
	if y then
		y = tonumber(y)
		m = tonumber(m)
	end
	if y and ((m > 12) or (m < 1)) then 
		y = false
		m = false
	elseif y then
		result.year = y
		result.month = m
		return result, false
	end
	
	-- try any method to extract year or month
	if not y then
		y = mw.ustring.match(date, "[%s%p%-–]?(%d%d%d%d)[%s%p%-–]?")
		if y then
			y = tonumber(y)
		end
		if y then
			result.year = y
		end
	end

	if y then
		if not m then
			m = mw.ustring.match(date, "[%s%p%-–]?(%w+)[%s%p%-–]?")
			if m then
				m = resources.monthparser[mw.ustring.lower(m)]
			end
			if m then
				result.month = m
			end
		end
	else
		-- reset only month
		result.month = nil
	end
	
	if y then
		return result, false
	end
end

local function collectAuthors(author, checkForAltFormat)
	if not author then
		return
	end
	
	-- Obsługa cudzysłowów w autorach (treat quoted authors as-is)
	if (isInQuotes(mw.text.trim(author))) then
		local strippedAuthor = mw.text.trim(author, '"\t\r\n\f ')
		return { items = {strippedAuthor}, more=false, comma=false, etal=false, separator="" }
	end
	
	
	function findUtf8CharAt(text, at)
		local back = false
		if at < 0 then
			at = #text + at + 1
			back = true
		end
		
		while at > 1 do
			local b = string.byte(text, at, at)
			if (b < 128) or (b >= 192) then
				break
			end
			
			at = at - 1
		end
		
		return back and at - #text - 1 or at
	end
	
	local etal = false
	local authorTail = #author <= 50 and author or string.sub(author, findUtf8CharAt(author, -50))
	for i, p in ipairs(resources.etalPatterns) do
		local a, e = string.match(authorTail, p)
		if a then
			author = string.sub(author, 1, #author-#e)
			etal = e
			break
		end
	end
	
	function decodeEntity(s)
		local result = nil
		local hex = string.match(s, "^&#[xX]([0-9A-Fa-f]+);$")
		if hex then
			result = mw.ustring.char(tonumber(hex, 16))
		else
			local dec = string.match(s, "^&#([0-9]+);$")
			if dec then
				result = mw.ustring.char(tonumber(dec, 10))
			elseif resources.htmlEntities[s] then
				result = mw.ustring.char(resources.htmlEntities[s])
			else
				return string.gsub(s, ";", "\\:")
			end
		end
		
		if result == ";" then
			return "\\:"
		elseif result == "," then
			return "\\."
		elseif result == "\\" then
			return "\\\\"
		else
			return result
		end
	end
	
	local authorHead = #author <= 500 and author or string.sub(author, 1, findUtf8CharAt(author, 500) - 1)
	local result = {}
	local esc1 = string.gsub(authorHead, "\\", "\\\\")
	local esc2 = string.gsub(esc1, "&#?[a-zA-Z0-9]+;", decodeEntity)
	local splitter = string.match(esc2, ";") and ";" or ","
	local authors = mw.text.split(esc2, splitter.."%s*", false)
	local nth = false
	local count = #authors
	if (#authorHead < #author) and (count > 4) then
		if count > 5 then
			table.remove(authors, count)
			count = count - 1
		end
		
		local at, _ = string.find(authorHead, authors[count], 1, true)
		nth = string.sub(author, at)
		table.remove(authors, count)
		count = count - 1
	end
	
	local alt = false
	if (splitter == ",") and checkForAltFormat then
		local altAuthors = {}
		alt = true
		for i, v in ipairs(authors) do
			local n0 = ""
			local s, n = mw.ustring.match(v, "^(%u%l+)%s(%u+)%.?$")
			if not s then
				s, n = mw.ustring.match(v, "^(%u%l+[%s%-–]%u%l+)%s(%u+)%.?$")
			end
			if not s then
				n0, s, n = mw.ustring.match(v, "^(%l%l%l?)%s(%u%l+)%s(%u+)%.?$") -- de, von, van, der etc.
			end
			if not s then
				alt = false
				break
			end
			local initials, _ = mw.ustring.gsub(n, "(%u)", "%1.")
			if #n0 > 0 then
				n0 = " "..n0
			end
			table.insert(altAuthors, s..", "..initials..n0)
		end
		
		if alt then
			authors = altAuthors
			splitter = ";"
		end
	end
	
	for i, v in ipairs(authors) do
		local author = parseAuthor(v)
		if author then
			table.insert(result, author)
		end
	end

	if #result == 0 then
		return
	end
	
	local check = false
	if alt then
		check = "alt"
	elseif (#result == 2) and (splitter == ",") then
		check = not result[1].link and not result[1].exact and not result[1].name
			or	not result[2].link and not result[2].exact and not result[2].name
		if check then
			if result[1].lastname and not result[1].name and not result[2].exact
			and not mw.ustring.match(result[1].lastname, "%S%s+%S") then
				local oneAuthor = parseAuthor(author)
				if oneAuthor then
					table.remove(result,2)
					result[1] = oneAuthor
					check = false
				end
			end
		end
		if check then
			mw.logObject(result,"przecinek u autora")
		end
	end
	
	return { items = result, more=nth, comma = check, etal = etal, separator=splitter.." " }
end
	
local function formatAuthors(authors, useDecorations, nextgroup, etalForm)
	local count = #authors.items
	if count == 0 then
		return nil, false
	end
	
	local suffix = function(author)
		if useDecorations then
			for _, v in ipairs(resources.authorFunc) do
				if checkPatterns(author, v.prefixes, v.suffixes) then
					return v.append
				end
			end
		end
		
		return ""
	end
	
	local formatter = function(author)
		local a = author:format(nextgroup)
		local r = author.link and ("[["..author.link.."|"..a.."]]") or a
		return r..suffix(author)
	end
	
	if count == 1 then
		local a1 = formatter(authors.items[1])
		local etal = authors.etal and (etalForm or " i inni") or ""
		return a1..etal, false
	end
	
	local result = {}
	table.insert(result, formatter(authors.items[1]))
	if not authors.etal and (count <= 3) then
		table.insert(result, ", ");
		table.insert(result, formatter(authors.items[2]))
		if count == 3 then
			table.insert(result, ", ");
			table.insert(result, formatter(authors.items[3]))
		end
		
		return table.concat(result, ""), false
	end

	local title = {}
	for i = 1, count do
		table.insert(title, authors.items[i]:towiki()..suffix(authors.items[i]))
	end
	if authors.more then
		table.insert(title, authors.more)
	end
	
	table.insert(result, "<span class=\"cite-at-al\" title=\"")
	table.insert(result, table.concat(title, authors.separator))
	if authors.etal then
		table.insert(result, etalForm or " i inni")
	end
	table.insert(result, "\">")
	table.insert(result, etalForm or " i inni")
	table.insert(result, "</span>")
	return table.concat(result, ""), true
end

local function collectLanguages(value)
	if value then
		local result = {}
		local values = mw.text.split(value, "%s+")
		for _, v in ipairs(values) do
			if #v > 0 then
				table.insert(result, v)
			end
		end
	
		if #result > 0 then
			return result
		end
	end

	return nil
end

local function splitWikiLink(text)
	local link, description = mw.ustring.match(text, "^%[%[(.-)%|(.-)%]%]$")
	if link then
		return description, link, false
	end
	
	local link = mw.ustring.match(text, "^%[%[(.-)%]%]$")
	if link then
		return link, link, false
	end
	
	local link, description = mw.ustring.match(text, "^%[(%S*)%s+(.-)%]$")
	if link and checkUri(link) then
		return description, false, link
	end
	
	return text, false, false
end

local function detectArchive(url)
	local defaultDecoder = resources.archiveDecoders.defaultDecoder
	for i, v in ipairs(resources.archiveDecoders) do
		local pattern = type(v) == "string" and v or v.pattern
		local decoder = type(v) == "table" and v or defaultDecoder
		local items = { mw.ustring.match(url, pattern) }
		if #items > 0 then
			return items[decoder.link], items[decoder.year].."-"..items[decoder.month].."-"..items[decoder.day]
		end
	end
	
	return false, false
end

local function isAutoGeneratedUrl(url)
	local address = string.gsub(url, "^https?:", "")
	for k, v in pairs(resources.params) do
		if v.link then
			local links = type(v.link) == "table" and v.link or { v.link }
			for _, vlink in ipairs(links) do
				local prefix = string.gsub(vlink, "^https?:", "")
				if (#address > #prefix) and (string.sub(address, 1, #prefix) == prefix) then
					return true
				end
			end
		end
	end

	return false
end

local function loadCitation(frame, mode)
	local result = {}

	-- copy parameters
	for k, v in pairs(resources.params) do
		if v.used[mode] then
			local value = frame.args[v.name]
			if value then
				value = mw.text.trim(value)
				if #value > 0 then
					result[k] = value
				end
			end
		
			if (v.used[mode] == "!") and not result[k] then
				-- simulate missing mandatory parameter
				result[k] = "{{{"..v.name.."}}}"
				if not result.missing then
					result.missing = v.name
				end
			end
		end
	end
	
	-- check url argument
	if result.url == "nie" then
		result.url = false
	elseif result.url then
		if not checkUri(result.url) then
			local unstrip = mw.text.unstripNoWiki( result.url )
			result.url = false
			if unstrip then
				result.urlnowiki = checkUri(unstrip)
			end
		end
	end

	-- translate some parameters
	local altAuthorParser = false
	if result.journal and result.pmid and result.author and not result.chapterauthor and not result.editor and not result.others then
		altAuthorParser = true
	end
	
	result.chapterauthor = collectAuthors(result.chapterauthor, false)
	result.author = collectAuthors(result.author, altAuthorParser)
	result.lang = collectLanguages(result.lang)
	result.editor = collectAuthors(result.editor, false)
	result.others = collectAuthors(result.others, false)

	-- parse main bibliographic date
	if result.date then
		local bibDate = false
		local bibDateHint = false
		local coinsDate = false
		local odnDate = false
		for _, v in ipairs(resources.bibDates) do
			for _, p in ipairs(v.patterns) do
				local bib, c = mw.ustring.gsub(result.date, p, v.show)
				if bib and (c > 0) then
					bibDate = bib
					bibDateHint = v.hint
					if v.coins then
						local cd, cc = mw.ustring.gsub(result.date, p, v.coins)
						if cd and (cc > 0) then
							coinsDate = cd
						end
					end

					if v.odn then
						local od, oc = mw.ustring.gsub(result.date, p, v.odn)
						if od and (oc > 0) then
							odnDate = od
						end
					end
					
					break
				end
				
				if bibDate then
					break
				end
			end
		end

		if bibDate then
			result.date = { bib = bibDate, hint = bibDateHint, coins = coinsDate, odn = odnDate }
		else
			local date, patch = parseDate(result.date or "", false, false, true)
			if date then
				date.coins = (patch and date.year)
					or (date.day and string.format("%04d-%02d-%02d", date.year, date.month, date.day)) 
					or (date.month and string.format("%04d-%02d", date.year, date.month))
					or date.year
				date.odn = date.year
			elseif result.date then
				result.badDate = true
			end
			
			result.date = date
			result.patchCitoidDate = patch
		end
	end

	-- fix other dates
	if result.accessdate then
		result.accessdate = parseDate(result.accessdate or "", false, false, false)
		if result.accessdate and not result.accessdate.day then
			result.badAccessDate = true
			result.accessdate = nil
		elseif not result.accessdate then
			result.badAccessDate = true
		end
	end

	-- allow more ISBN numbers
	if result.isbn then
		-- TODO allow "(info)" for custom description followed each identifier
		result.isbn = mw.text.split(result.isbn, "%s+")
	end
	
	if result.title then
		local url
		result.title, result.titlelink, url = splitWikiLink(result.title)
		if url or result.titlelink then
			if result.url and (#result.url > 0) and (result.url ~= "{{{url}}}") then
				result.urlWarning = true
			end
			
			result.url = url
		end
	end
	if result.chapter then
		result.chapter, result.chapterlink, result.chapterurl = splitWikiLink(result.chapter)
	end
	if result.journal then
		local journalAbbr, _ = mw.ustring.gsub(result.journal, "[%.%s]+", " ")
		mw.logObject(journalAbbr, "journalAbbr")
		if mw.ustring.match(journalAbbr, "^[%a%s]+[,:]?[%a%s]+%d?$") -- kandydat na skrót powinien mieć tylko litery z opcjonalnymi odstępami i co najwyżej jednym dwukropkiem lub przecinkiem
		or mw.ustring.match(journalAbbr, "^[%a%s]+%([%a%s,]+%)$") then -- opcjonalnie jakieś dookreślenie w nawiasie
			local expandedJournal = mw.loadData("Moduł:Cytuj/czasopisma")[mw.text.trim(journalAbbr)]
			if expandedJournal then
				result.originalJournal = result.journal
				result.journal = expandedJournal
			end
		end
		result.journal, result.journallink, result.journalurl = splitWikiLink(result.journal)
	end
	if result.journal and not result.journallink and not result.journalurl and not result.title and result.url then
		result.journalurl = result.url
		result.url = false
	end

	if result.url and isAutoGeneratedUrl(result.url) then
		result.rejectedurl = true
		result.url = false
	end
	if result.chapterurl and isAutoGeneratedUrl(result.chapterurl) then
		result.rejectedurl = true
		result.chapterurl = false
	end
	if result.journalurl and isAutoGeneratedUrl(result.journalurl) then
		result.rejectedurl = true
		result.journalurl = false
	end

	if not result.archive and result.url then
		local al, ad = detectArchive(result.url)
		if al then
			result.archiveurl = true
			result.archive = result.url
			result.url = al
			if ad then result.archived = ad end
		end
	elseif not result.archive and result.chapterurl then
		local al, ad = detectArchive(result.chapterurl)
		if al then
			result.archivechapter = true
			result.archive = result.chapterurl
			result.chapterurl = al
			if ad then result.archived = ad end
		end
	elseif not result.archive and result.journalurl then
		local al, ad = detectArchive(result.journalurl)
		if al then
			result.archivejournal = true
			result.archive = result.journalurl
			result.journalurl = al
			if ad then result.archived = ad end
		end
	elseif result.archive and not result.archived then
		local al, ad = detectArchive(result.archive)
		if ad and not result.archived then result.archived = ad	end
	end
	
	if result.archive then
		if result.chapterurl and not result.url then
			result.archivechapter = true
		elseif result.title then
			result.archiveurl = true
		elseif result.journal then
			result.archivejournal = true
		end
	end

	if result.archived then
		result.archived = parseDate(result.archived or "", false, false, false)
		if result.archived and not result.archived.day then
			result.badArchivedDate = true
			result.archived = null
		elseif not result.archived then
			result.badArchivedDate = true
		end
	end

	if result.edition and result.journal and not result.volume and not result.issue then
		local volume, issue = mw.ustring.match(result.edition, "^%s*([^%(]+)%s+%((.-)%)%s*$");
		if volume then
			result.volume = volume
			result.issue = issue
			result.edition = nil
		end
	end

	if result.pmc and (#result.pmc > 3) and (mw.ustring.sub(result.pmc, 1, 3) == "PMC") then
		result.pmc = mw.ustring.sub(result.pmc, 4, #result.pmc)
	end

	if result.accessKind then
		result.accessKind = access.choice[result.accessKind]
		result.unknownAccess = not result.accessKind
	else
		result.accessKind = (result.pmc and "open")
			or access.doi[doiPrefix]
			or access.journals[result.journal]
	end

	if result.doi then
		result.doi = mw.text.split(result.doi, '%s+', false)
		for i, v in ipairs(result.doi) do
			local doiPrefix
			local doiSuffix
			doiPrefix, doiSuffix = mw.ustring.match(v, "^10%.([^/]+)/(.+)$")
			if (doiPrefix == "2307") and not result.jstor then
				result.jstor = doiSuffix
			end
			if not result.accessKind and not result.unknownAccess then
				result.accessKind = access.doi[doiPrefix]
			end
		end
	end
	
	if result.patent then
		mw.logObject(result.patent,"input:patent")
		local patentPatterns = mw.loadData("Moduł:Brudnopis/Paweł Ziemian/Cytuj/patent")
		local patent = nil
		for _, v in ipairs(patentPatterns) do
			if string.match(result.patent, v.pattern) then
				local patentNumber, _ = string.gsub(result.patent, v.pattern, v.number or "%1")
				local patentCountry, _ = string.gsub(result.patent, v.pattern, v.country)
				local patentInfo = v.info or patentPatterns.ccinfo[patentCountry]
				if (result.url == nil) and v.url then
					local url, _ = string.gsub(result.patent, v.pattern, v.url)
					if checkUri(url) then
						result.url = url
					end
				end
				
				local patentTitle
				if v.title then
					patentTitle, _ = string.gsub(result.patent, v.pattern, v.title)
				elseif patentInfo then
					patentTitle =  string.format('<span title="%s">%s %s</span>', patentInfo, patentCountry, patentNumber)
				else
					patentTitle =  patentCountry.." "..patentNumber
				end

				patent = {
					number = patentNumber,
					application = v.application,
					country = patentCountry,
					title = patentTitle,
				}
				
				break
			end
		end
		
		result.patent = patent
		mw.logObject(result.patent,"parsed:patent")
	end

	-- return collected parameters if there is any	
	for k, v in pairs(result) do
		return result
	end
	
	-- there are no supported parameters
	return nil
end

local function prepareOdnIdentifier(data)
	if not data.odn or (#data.odn == 0) or (data.odn == "nie") then
		return nil
	end

	data.diferentiator = mw.ustring.match(data.odn, "^([a-z])$") or false
	if data.odn ~= "tak" and not data.diferentiator then
		-- TODO return only CITEREF...
		return data.odn
	end
	
	local authors = data.chapterauthor or data.author or data.editor
	if not authors then
		-- required custom identifier
		return nil
	end
	
	return "CITEREF"
		.. (authors.items[1] and (authors.items[1].lastname or authors.items[1].exact) or "")
		.. (authors.items[2] and (authors.items[2].lastname or authors.items[2].exact) or "")
		.. (authors.items[3] and (authors.items[3].lastname or authors.items[3].exact) or "")
		.. (authors.items[4] and (authors.items[4].lastname or authors.items[4].exact) or "")
		.. (data.date and data.date.odn or "")
		.. (data.diferentiator or "")
end

local function bookCOinS(data)
	local authors = data.chapterauthor or data.author
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:book"
	if data.chapter and (#data.chapter > 0) then
		result["rft.gengre"] = "bookitem"
		result["rft.atitle"] = plainText(data.chapter)
		result["rft.btitle"] = plainText(data.title)
	elseif data.work and (#data.work > 0) then
		result["rft.gengre"] = "bookitem"
		result["rft.atitle"] = plainText(data.title)
		result["rft.btitle"] = plainText(data.work)
	else
		result["rft.btitle"] = plainText(data.title)
		result["rft.gengre"] = "book"
	end
	if authors then
		if authors.items[1].lastname then result["rft.aulast"] = authors.items[1].lastname end
		if authors.items[1].name then result["rft.aufirst"] = authors.items[1].name end
		if authors.items[1].exact then result["rft.au"] = authors.items[1].exact end
	end
	if data.date and data.date.coins then
		result["rft.date"] = data.date.coins
	end
	if data.series then result["rft.series"] = data.series end
	if data.edition then result["rft.edition"] = data.edition end
	if data.publisher then result["rft.pub"] = data.publisher end
	if data.place then result["rft.place"] = data.place end
	if data.pages then result["rft.pages"] = data.pages end
	if data.isbn then result["rft.isbn"] = data.isbn[1] end
	if data.issn then result["rft.issn"] = data.issn end
	
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.oclc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:oclcnum/"..data.oclc})) end
	if data.doi then
		for _, v in ipairs(data.doi) do
			table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..v}))
		end
	end
	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
	if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
	if data.lccn then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:lccn/"..data.lccn})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end

local function journalCOinS(data)
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal"
	local gengre = (data.arxiv and (#data.arxiv > 0)) and "preprint" or "article"
	result["rft.gengre"] = data.title and gengre or "journal"
	if data.title then result["rft.atitle"] = plainText(data.title) end
	result["rft.jtitle"] = plainText(data.journal)
	if data.chapter then result["rft.atitle"] = plainText(data.chapter) end
	if data.date and data.date.coins then
		result["rft.date"] = data.date.coins
	end
	if data.title and author then
		if author[1].lastname then result["rft.aulast"] = author[1].lastname end
		if author[1].name then result["rft.aufirst"] = author[1].name end
		if author[1].exact then result["rft.au"] = author[1].exact end
	end
	if data.volume then result["rft.volume"] = data.volume end
	if data.issue then result["rft.edition"] = data.issue end
	if data.publisher then result["rft.pub"] = data.publisher end
	if data.place then result["rft.place"] = data.place end
	if data.pages then result["rft.pages"] = data.pages end
	if data.issn then result["rft.issn"] = data.issn end
	
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
	if data.pmc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmc/"..data.pmc})) end
	if data.doi then
		for _, v in ipairs(data.doi) do
			table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..v}))
		end
	end
	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end

local function webCOinS(data)
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal"
	result["rft.gengre"] = "unknown"
	if data.title then result["rft.atitle"] = plainText(data.title) end
	result["rft.jtitle"] = plainText(data.published)
	if data.date and data.date.coins then
		result["rft.date"] = data.date.coins
	end
	if data.title and author then
		if author[1].lastname then result["rft.aulast"] = author[1].lastname end
		if author[1].name then result["rft.aufirst"] = author[1].name end
		if author[1].exact then result["rft.au"] = author[1].exact end
	end
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end

local function patentCOinS(data)
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal"
	if data.title then result["rft.title"] = plainText(data.title) end
	result[data.patent.application and "rft.applnumber" or "rft.number"] = data.patent.number
	result["rft.cc"] = data.patent.country
	if data.date and data.date.coins then
		result[data.patent.application and "rft.appldate" or "rft.date"] = data.date.coins
	end
	if author then
		if author[1].lastname then result["rft.aulast"] = author[1].lastname end
		if author[1].name then result["rft.aufirst"] = author[1].name end
		if author[1].exact then result["rft.au"] = author[1].exact end
	end
	-- rft.assignee = author (wszyscy?)
	-- rft.inventor = others (wszyscy?)
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end


local function COinS(data, coinsFormat)
	if resources.abbrTitles[data.title] then
		-- full citation is elsewhere
		return false
	elseif (coinsFormat == "info:ofi/fmt:kev:mtx:book") and data.title and (#data.title > 0) then
		-- title is mandatory element for books
		return bookCOinS(data)
	elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.journal and (#data.journal > 0) and (not data.published or (data.journal ~= data.published)) then
		-- journal title is mandatory element for journals
		return journalCOinS(data)
	elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.published and (#data.published > 0) then
		return webCOinS(data)
	elseif coinsFormat == "info:ofi/fmt:kev:mtx:patent" and data.patent then
		return patentCOinS(data)
	elseif data.title and (#data.title > 0) then
		-- treat web or unrecognized citations as book
		return bookCOinS(data)
	else
		return false
	end
end

local function Cite(p, mode, appendText)
	-- debug helper
	if p.args[3] then mw.log(p.args[3]) end
	local customMode = mode

	-- try to determine type basing on passed parameters
	local coinsFormat = resources.COinS[mode]
	if not mode then
		mode, coinsFormat = determineMode(p)
	end
	
	local data = loadCitation(p, mode)
	if not data then
		return resources.categories.empty
	end
	if data.missing then
		-- do not produce any COiNS info
		-- if some mandatory argument is missing
		coinsFormat = false
	end

	local builder = mw.html.create("cite")
	builder
		:addClass("citation")
		:addClass(resources.cite[mode] or nil)
		:addClass(access.class[data.accessKind])
		:attr("id", prepareOdnIdentifier(data))
		--:wikitext(access.render[data.accessKind], ' ')

	local needDot = false
	local nextAuthorGroup = false
	if data.title or data.patent then
		
		if data.chapter then
			local authors = data.editor and data.author or data.chapterauthor
			if authors then
				local list, etal = formatAuthors(authors, false, nextAuthorGroup, nil)
				builder:wikitext(list, ", ")
				nextAuthorGroup = true
			end
			
			local title = softNoWiki(data.chapter)
			if data.chapterurl then
				builder:wikitext("[", escapeUrl(data.archivechapter and data.archive or data.chapterurl), " ''", title, "'']")
			elseif data.chapterlink then
				builder:wikitext("[[", data.chapterlink, "|''", title, "'']]")
			else
				builder:wikitext("''", title, "''")
			end
			
			if data.format then
				builder:wikitext(" &#x5B;", data.format, "&#x5D;")
			end

			builder:wikitext(", [w:] ")
		end

		local authors = false
		local editor = false
		if not data.chapter and data.author then
			authors = data.author
		else
			authors = data.editor or data.author
			editor = data.editor
		end
		if authors then
			local list, etal = formatAuthors(authors, not (editor or false), nextAuthorGroup, editor and " i inni red." or nil)
			builder:wikitext(list)
			nextAuthorGroup = true
			if editor and not etal and not authors.etal then
				builder:wikitext(" (red.)")
			end
			builder:wikitext(", ")
		end
		if customMode and data.authorextra then
			builder:wikitext(data.authorextra, ", ")
		end
		
		if resources.abbrTitles[data.title] then
			local title = resources.abbrTitles[data.title]
			builder:wikitext(title)
			needDot = not mw.ustring.match(title, "%.%]%]$")
				and not mw.ustring.match(title, "%.$")
		elseif data.title then
			local title = softNoWiki(data.title)
			if data.url or data.archiveurl then
				builder:wikitext("[", escapeUrl(data.archiveurl and data.archive or data.url), " ''", title, "'']")
			elseif data.titlelink then
				builder:wikitext("[[", data.titlelink, "|''", title, "'']]")
			else
				builder:wikitext("''", title, "''")
			end
			if not data.chapter and data.format then
				builder:wikitext(" &#x5B;", data.format, "&#x5D;")
				needDot = true
			elseif not mw.ustring.match(plainText(title), "[%.,!?]$") then
				needDot = true
			end
	
			local showmediatype = data.mediatype and (#data.mediatype > 0)
			if showmediatype then
				builder:wikitext(" &#x5B;", data.mediatype, "&#x5D;")
				needDot = true
			end
		end

		if not editor and data.editor then
			local list, etal = formatAuthors(data.editor, false, true, " i inni red.")
			builder:wikitext(needDot and ", " or " ", list, (etal or data.editor.etal) and "" or " (red.)")
			needDot = true
		end
		
		if data.others then
			local list, etal = formatAuthors(data.others, true, true, nil)
			builder:wikitext(needDot and ", " or " ", data.patent and resources.patent.inventor.." " or "", list)
			needDot = true
		end

		if data.patent then
			local title = (not data.title and data.url) and string.format("[%s %s]", escapeUrl(data.url), data.patent.title) or data.patent.title
			builder:wikitext(needDot and ", " or " ", resources.patent[data.patent.application], " ", title)
			needDot = true
		end
	elseif data.journal and data.author then
		local list, etal = formatAuthors(data.author, false, false, nil)
		builder:wikitext(list, ", ")
	end

	if data.work then
		builder:wikitext((data.title or data.patent) and ", " or "", "[w:] ", data.work, (not data.mediatype and data.url) and " [online]" or "")
		needDot = true
	end

	if data.journal and (not data.published or (data.journal ~= data.published)) then
		builder:wikitext((data.title or data.work) and ", " or "")
		local title = softNoWiki(data.journal)
		if data.journalurl or data.archivejournal then
			builder:wikitext("[", escapeUrl(data.archivejournal and data.archive or data.journalurl), " „", title, "”]")
		elseif data.journallink then
			builder:wikitext("„[[", data.journallink, "|", title, "]]”")
		else
			builder:wikitext("„", title, "”")
		end
		needDot = true
	end

	if data.responsibility then
		builder:wikitext(", ", data.responsibility)
		needDot = true
	end

	if data.edition then
		builder:wikitext(data.journal and ", " or ", wyd. ", data.edition)
		needDot = true
	end
	
	if data.volume then
		builder:wikitext(data.journal and ", " or ", t. ", data.volume)
		needDot = true
	end
	
	if data.journal and data.issue then
		builder:wikitext(" (", data.issue, ")")
		needDot = true
	end

	if data.description and (#data.description > 0) then
		builder:wikitext(", ", data.description)
		needDot = true
	end

	if data.published and not data.publisher then
		builder:wikitext(", ", data.published)
		needDot = true
	end

	local place = false
	if data.place then
		builder:wikitext(", ", data.place)
		needDot = true
		place = true
	end
	if data.publisher then
		builder:wikitext(place and ": " or ", ", data.publisher)
		needDot = true
		place = false
	end
	if data.date then
		local shortDate = data.journal and (data.doi or data.pmid or data.pmc)
		if data.date.bib and data.date.hint then
			builder:wikitext(place and " " or ", "):tag("span"):attr("title", data.date.hint):wikitext(data.date.bib)
		elseif data.date.bib  then
			builder:wikitext(place and " " or ", ", data.date.bib)
		elseif data.date.day and shortDate then
			builder:wikitext(place and " " or ", "):tag("span"):attr("title", tostring(data.date.day).." "..resources.months[data.date.month].d.." "..tostring(data.date.year)):wikitext(data.date.year)
		elseif data.date.month and shortDate then
			builder:wikitext(place and " " or ", "):tag("span"):attr("title", resources.months[data.date.month].m.." "..tostring(data.date.year)):wikitext(data.date.year)
		elseif data.date.day then
			builder:wikitext(", ", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year))
		elseif data.date.month then
			builder:wikitext(", ", resources.months[data.date.month].m, " ", tostring(data.date.year))
		else
			builder:wikitext(place and " " or ", ", data.date.year)
		end
		builder:wikitext(data.diferentiator or "")
		needDot = true
	end

	if not data.journal and (data.series or data.issue) then
		builder:wikitext(" (", data.series or "", (data.series and data.issue) and "; " or "", data.issue or "", ")")
		needDot = true
	elseif data.journal and data.series then
		builder:wikitext(" (", data.series, ")")
		needDot = true
	end
	
	if data.p and #data.p > 0 then
		local isNonStandardPageNumber = mw.ustring.match(data.p, "[^%s0-9,%-–]")
		builder:wikitext(isNonStandardPageNumber and ", " or ", s. ", data.p)
		needDot = true
	end
	
	if data.doi then
		local separator = "&nbsp;"
		builder:addClass("doi"):wikitext(", [[DOI (identyfikator cyfrowy)|DOI]]:")
		local doiLink = first(resources.params.doi.link)
		for _, v in ipairs(data.doi) do
			builder:wikitext(separator, "[", doiLink, mw.uri.encode(v), " ", softNoWiki(v), "]")
			separator = ", "
		end
		needDot = true
	end
	
	if data.isbn then
		for i,v in ipairs(data.isbn) do
			builder:wikitext(", ")
			require("Moduł:ISBN").link(builder, v)
		end

		needDot = true
	end

	if data.lccn then
		builder:wikitext(", [[Biblioteka Kongresu|LCCN]] [", first(resources.params.lccn.link), mw.uri.encode(data.lccn), " ", data.lccn, "]")
		needDot = true
	end
	
	if data.issn then
		builder:tag("span"):addClass("issn"):wikitext(", [[International Standard Serial Number|ISSN]] [", first(resources.params.issn.link), data.issn, " ", data.issn, "]")
		needDot = true
	end
	
	if data.pmid then
		builder:addClass("pmid"):wikitext(", [[PMID]]:&nbsp;[", first(resources.params.pmid.link), data.pmid, " ", data.pmid, "]")
		needDot = true
	end
	
	if data.pmc then
		builder:addClass("pmc"):wikitext(", [[PMCID]]:&nbsp;[", first(resources.params.pmc.link), data.pmc, "/ PMC", data.pmc, "]")
		needDot = true
	end
	
	if data.bibcode then
		builder:wikitext(", [[Bibcode]]:&nbsp;[", first(resources.params.bibcode.link), data.bibcode, " ", data.bibcode, "]")
		needDot = true
	end
	
	if data.oclc then
		builder:wikitext(", [[Online Computer Library Center|OCLC]]&nbsp;[", first(resources.params.oclc.link), mw.uri.encode(data.oclc), " ", data.oclc, "]")
		needDot = true
	end
	
	if data.arxiv then
		builder:wikitext(", [[arXiv]]:")
		local eprint, class = mw.ustring.match(data.arxiv, "^(%S+)%s+%[([^%[%]]+)%]$")
		if eprint then
			builder:wikitext("[", first(resources.params.arxiv.link), eprint, " ", eprint, "] &#x5B;[//arxiv.org/archive/", class, " ", class, "]&#x5D;" )
		else
			builder:wikitext("[", first(resources.params.arxiv.link), data.arxiv, " ", data.arxiv, "]" )
		end
		needDot = true
	end
	
	if data.jstor then
		builder:tag("span"):addClass("jstor"):wikitext(", [[JSTOR]]:&nbsp;[", first(resources.params.jstor.link), data.jstor, " ", data.jstor, "]")
		needDot = true
	end
	
	if data.ol then
		builder:tag("span"):addClass("open-library"):wikitext(", [[Open Library|OL]]:&nbsp;[", first(resources.params.ol.link), data.ol, " ", data.ol, "]")
		needDot = true
	end
	
	if data.id then
		builder:wikitext(", ", data.id)
		needDot = true
	end
	
	if data.accessdate then
		builder:tag("span"):addClass("accessdate"):wikitext(" [dostęp ", string.format("%04d-%02d-%02d", data.accessdate.year, data.accessdate.month, data.accessdate.day), "]")
		needDot = true
	end
	
	if data.archive then
		builder:wikitext(" [zarchiwizowane")
		local url = data.archiveurl and data.url or (data.archivechapter and data.chapterurl or data.journalurl)
		if url then
			builder:wikitext(" z [", escapeUrl(url), " adresu]")
		end
		if data.archived and data.archived.day then
			builder:wikitext(" ", string.format("%04d-%02d-%02d", data.archived.year, data.archived.month, data.archived.day))
		end
		builder:wikitext("]")
		needDot = true
	end
	
	if data.quotation then
		builder:wikitext(", Cytat: ", data.quotation)
		needDot = true
	end

	local coinsData = COinS(data, coinsFormat)
	if coinsData then
		builder:tag("span"):addClass("Z3988"):attr("title",coinsData):css("display","none"):wikitext("&nbsp;")
	end
	
	if data.lang then
		local languages = require("Moduł:Lang").lang({args = data.lang})
		builder:wikitext(" ", languages)
		needDot = true
	end
	
	if data.fullStop then
		if not mw.ustring.match(data.fullStop, "^[%.!?,;:]") then
			builder:wikitext(", ")
		end
		builder:wikitext(data.fullStop)
		needDot = mw.ustring.match(data.fullStop, "[%.!?,;:]$") == nil
	end

	if needDot then
		builder:wikitext(".")
	end

	if appendText then
		builder:wikitext(appendText)
	end
	
	-- categories
	local addCategories = mw.title.getCurrentTitle().namespace == 0
	local problems = {}
	if not customMode and (mode == 1) then
		builder:wikitext(resources.categories.undetermined)
		table.insert(problems, "???")
	end
	if data.publisher and data.published then
		table.insert(problems, "p?")
		if addCategories then
			table.insert(problems, resources.categories.unusedPublished)
		end
	end
	if data.journal and data.published and (data.journal == data.published) then
		table.insert(problems, "j?")
		if addCategories then
			table.insert(problems, resources.categories.sameJournalAndPublished)
		end
	end
	
	if (not data.url and not data.chapterurl) or (not data.title and not data.journalurl) then
		builder:addClass(data.urlnowiki and "urlnowiki" or "nourl")
	end
	
	local missing = false
	local needurl = ((resources.params.published.used[mode] == "*") and data.published) or (resources.params.url.used[mode] == "*")
	if data.missing then
		-- usually missing title, this is the first check for mandatory arguments
		table.insert(problems, data.missing)
		missing = true
	elseif needurl and not data.url and not data.chapterurl and not data.arxiv and not data.archive then
		-- build in support for missing external link for page citation
		table.insert(problems, resources.params.url.name)
		missing = true
	else
		-- any other missing value (first catch)
		for k, v in pairs(resources.params) do
			if (v.used[mode] == "!") and (not data[k] or (#data[k] == 0)) then
				table.insert(problems, v.name)
				missing = true
				break
			end
		end
	end

	if missing and addCategories then
		builder:wikitext(string.format(resources.categories.missingArg, resources.modes[mode]))
	end
	if (data.chapterauthor and data.chapterauthor.comma)
	or (data.author and (data.author.comma == true))
	or (data.editor and data.editor.comma)
	or (data.others and data.others.comma) then
		table.insert(problems, "!!!")
		if addCategories then
			builder:wikitext(resources.categories.suspectedComma)
		end
	end
	if data.author and (data.author.comma == "alt") then
		table.insert(problems, "a?")
		if addCategories then
			builder:wikitext(resources.categories.altAuthor)
		end
	end
	if data.originalJournal then
		table.insert(problems, "c?")
		if addCategories then
			builder:wikitext(resources.categories.altJournal)
		end
	end
	local citewiki = (data.journal and mw.ustring.match(data.journal, "[Ww]ikipedia"))
		or (data.publisher and mw.ustring.match(data.publisher, "[Ww]ikipedia"))
		or (data.published and mw.ustring.match(data.published, "[Ww]ikipedia"))
		or (data.url and mw.ustring.match(data.url, "%.wikipedia%.org"))
	if citewiki then
		table.insert(problems, "wiki?")
		if addCategories then
			builder:wikitext(resources.categories.wiki)
		end
	end
	if data.unknownAccess then
		table.insert(problems, "dostęp?")
		if addCategories then
			builder:wikitext(resources.categories.unknownAccess)
		end
	end
	if data.rejectedurl then
		table.insert(problems, "<s>url</s>")
		if addCategories then
			builder:wikitext(resources.categories.rejectedUrl)
		end
	end
	if data.urlWarning then
		table.insert(problems, "Url")
		if addCategories then
			builder:wikitext(resources.categories.unusedUrl)
		end
	end
	if data.patchCitoidDate then
		table.insert(problems, "1 stycznia")
	end
	if data.badDate then
		table.insert(problems, "data?")
	end
	if data.badAccessDate then
		table.insert(problems, "data dostępu?")
	end
	if data.badArchivedDate then
		table.insert(problems, "zarchiwizowano?")
	end
	if addCategories and (data.badDate or data.badAccessDate or data.badArchiveDate) then
		builder:wikitext(resources.categories.badDate)
	end
	if (data.author and data.author.etal)
	or (data.chapterauthor and data.chapterauthor.etal)
	or (data.editor and data.editor.etal)
	or (data.others and data.others.etal) then
		table.insert(problems, "i inni")
		if addCategories then
			builder:wikitext(resources.categories.etal)
		end
	end

	if #problems > 0 then
		local info = builder:tag("span")
			:addClass("problemy")
			:addClass("problemy-w-cytuj")
			:attr("aria-hidden", "true")
			:attr("data-nosnippet", "")
		info:wikitext(table.concat(problems,", "))
	end
	
	return builder:done()
end

return {
	
auto = function(frame)
	return Cite(frame:getParent(), nil, nil)
end,

custom = function(frame)
	local traceCategory = false
	local pagename = mw.title.getCurrentTitle()
	if (pagename.namespace == 10) and frame.getParent then
		local template = mw.title.new( frame:getParent():getTitle(), "Szablon" )
		if mw.title.compare(template, pagename) == 0 then
			traceCategory = resources.categories.traceInvokeCustom
		end
	end
	
	local customMode = frame.args[1]
	local mode = 1
	if customMode then
		customMode = mw.text.trim(customMode)
		for i, v in ipairs(resources.modes) do
			if customMode == v then
				mode = i
				break
			end
		end
	end

	return Cite(frame, mode, traceCategory)
end,

}