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

Z Czarnobyl Wiki
Skocz do: nawigacja, szukaj
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 = {
 
empty = "[[Kategoria:Szablon cytowania bez parametrów]]",
 
undetermined = "[[Kategoria:Szablon cytowania bez określonego trybu]]",
 
missingArg = "[[Kategoria:Szablon cytowania w trybie 'cytuj %s' bez obowiązkowych parametrów]]",
 
suspectedComma = "[[Kategoria:Szablon cytowania zawiera przecinek w polu z opisem autora]]",
 
unusedUrl = "[[Kategoria:Szablon cytowania zawiera nieużywany URL]]",
 
unusedPublished = "[[Kategoria:Szablon cytowania zawiera pola 'opublikowany' i 'wydawca']]",
 
sameJournalAndPublished = "[[Kategoria:Szablon cytowania zawiera identyczne pola 'czasopismo' i 'opublikowany']]",
 
},
 
 
--[[
 
; 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)
Linia 218: Linia 15:
 
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 293: Linia 94:
  
 
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 119:
 
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 127:
  
 
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 135:
 
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 170:
  
 
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
 
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 228:
 
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 254:
 
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 277:
 
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 583: Linia 415:
 
end
 
end
  
local function loadAuthor(frame, params, index)
+
local function collectAuthors(author, checkForAltFormat)
local argAuthor = formatDynamicArgName(params.author.name, index)
+
if not author then
 
 
local result = false
 
local author = frame.args[argAuthor]
 
if author and (#author > 0) then
 
result = parseAuthor(author)
 
end
 
 
 
if not result then
 
 
return
 
return
 
end
 
end
 
+
local first = frame.args[argFirst]
+
function decodeEntity(s)
if first and (#first > 0) then
+
local result = nil
result.name = first
+
local hex = string.match(s, "^&#[xX]([0-9A-Fa-f]+);$")
result.nameinitials = makeInitials(first)
+
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
 
end
 
 
local link = frame.args[argLink]
+
local result = {}
if link and (#link > 0) then
+
local esc1 = string.gsub(author, "\\", "\\\\")
result.link = link
+
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 alt = false
 +
if (splitter == ",") and checkForAltFormat then
 +
local altAuthors = {}
 +
alt = true
 +
for _, 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
 
end
 
return result
 
end
 
  
local function collectAuthors(author)
 
if not author then
 
return
 
end
 
 
local result = {}
 
local splitter = string.match(author, ";") and ";" or ","
 
local authors = mw.text.split(author, splitter, true)
 
 
for _, v in ipairs(authors) do
 
for _, v in ipairs(authors) do
 
local author = parseAuthor(v)
 
local author = parseAuthor(v)
Linia 629: Linia 493:
 
end
 
end
 
 
return result, (#result == 2) and (separator == ",")
+
local check = false
 +
if alt then
 +
check = "alt"
 +
elseif (#result == 2) and (separator == ",") then
 +
check = true
 +
end
 +
 +
return result, check
 
end
 
end
 
 
Linia 641: Linia 512:
 
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 ""
+
local s = ""
 +
if useDecorations then
 +
for _, v in ipairs(resources.authorFunc) do
 +
if checkPatterns(author, v.prefixes, v.suffixes) then
 +
s = v.append
 +
break
 +
end
 +
end
 +
end
 +
 
return r..s
 
return r..s
 
end
 
end
Linia 663: Linia 543:
 
end
 
end
 
 
table.insert(result, "<span class=\"cite-more-full\">")
 
 
local title = {}
 
local title = {}
 
for i = 2, count do
 
for i = 2, count do
table.insert(result, ", ");
 
table.insert(result, formatter(authors[i]))
 
 
table.insert(title, authors[i]:towiki())
 
table.insert(title, authors[i]:towiki())
 
end
 
end
table.insert(result, "</span>")
 
 
table.insert(result, "<span class=\"cite-at-al\" title=\"")
 
table.insert(result, "<span class=\"cite-at-al\" title=\"")
 
table.insert(result, table.concat(title, ", "))
 
table.insert(result, table.concat(title, ", "))
Linia 716: Linia 592:
 
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 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?://.*)$")
 +
if y then
 +
return link, y.."-"..m.."-"..d
 +
end
 +
 +
local y, m, d, link = mw.ustring.match(url, "^https?://webarchive%.nationalarchives%.gov%.uk/(%d%d%d%d)(%d%d)(%d%d)%d%d%d%d%d%d/(https?://.*)$")
 
if y then
 
if y then
 
return link, y.."-"..m.."-"..d
 
return link, y.."-"..m.."-"..d
Linia 721: Linia 602:
 
 
 
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 748: Linia 646:
  
 
-- 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, result.chapterComma = collectAuthors(result.chapterauthor, false)
 +
result.author, result.authorComma = collectAuthors(result.author, altAuthorParser)
 
result.lang = collectLanguages(result.lang)
 
result.lang = collectLanguages(result.lang)
result.editor, result.editorComma = collectAuthors(result.editor)
+
result.editor, result.editorComma = collectAuthors(result.editor, false)
result.others, result.othersComma = collectAuthors(result.others)
+
result.others, result.othersComma = 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
 +
end
 +
 +
result.date = date
 +
result.patchCitoidDate = patch
 +
end
 
end
 
end
  
Linia 793: Linia 737:
 
end
 
end
 
if result.journal then
 
if result.journal then
 +
local journalAbbr, _ = mw.ustring.gsub(result.journal, "[%.%s]+", " ")
 +
if mw.ustring.match(journalAbbr, "^[%a%s]+:?[%a%s]+$") then  -- kandydat na skrót powinien mieć tylko litery z opcjonalnymi odstępami i co najwyżej jednym dwukropkiem
 +
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.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 803: Linia 768:
 
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.archive = result.chapterurl
 +
result.chapterurl = al
 +
if ad then result.archived = ad end
 +
end
 +
elseif result.archive and (not (result.url or result.chapterurl) or 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 al and not (result.url or result.chapterurl) 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
 
end
Linia 814: Linia 786:
 
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
 +
 +
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
 
end
 
end
Linia 854: Linia 855:
 
.. (authors[3] and (authors[3].lastname or authors[3].exact) or "")
 
.. (authors[3] and (authors[3].lastname or authors[3].exact) or "")
 
.. (authors[4] and (authors[4].lastname or authors[4].exact) or "")
 
.. (authors[4] and (authors[4].lastname or authors[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 879: Linia 880:
 
if authors[1].exact then result["rft.au"] = authors[1].exact end
 
if authors[1].exact then result["rft.au"] = authors[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.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 896:
  
 
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 917:
 
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 925:
 
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 939:
 
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 956:
 
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 989: Linia 995:
 
-- 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 1010: Linia 1017:
 
:addClass("citation")
 
:addClass("citation")
 
:attr("id", prepareOdnIdentifier(data))
 
:attr("id", prepareOdnIdentifier(data))
 +
:wikitext(access.render[data.accessKind], ' ')
  
 
local needDot = false
 
local needDot = false
Linia 1031: Linia 1039:
 
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
  
Linia 1053: Linia 1061:
 
end
 
end
 
builder:wikitext(", ")
 
builder:wikitext(", ")
 +
end
 +
if customMode and data.authorextra then
 +
builder:wikitext(data.authorextra, ", ")
 
end
 
end
 
 
Linia 1063: Linia 1074:
 
builder:wikitext("''", title, "''")
 
builder:wikitext("''", title, "''")
 
end
 
end
if not mw.ustring.match(plainText(title), "%p$") then
+
if not data.chapter and data.format then
 +
builder:wikitext(" &#x5B;", data.format, "&#x5D;")
 +
needDot = true
 +
elseif not mw.ustring.match(plainText(title), "%p$") then
 
needDot = true
 
needDot = true
 
end
 
end
Linia 1084: Linia 1098:
 
 
 
if data.work then
 
if data.work then
builder:wikitext(", [w:] ", data.work, (not data.mediatype and data.url) and " [online]" or "")
+
builder:wikitext(" [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 " [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)
Linia 1108: Linia 1122:
 
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.series or data.issue then
 +
builder:wikitext(" (", data.series or "", (data.series and data.issue) and "; " or "", data.issue or "", ")")
 
needDot = true
 
needDot = true
 
end
 
end
 
+
 
if data.description and (#data.description > 0) then
 
if data.description and (#data.description > 0) then
 
builder:wikitext(", ", data.description)
 
builder:wikitext(", ", data.description)
Linia 1141: Linia 1159:
 
end
 
end
 
if data.date then
 
if data.date then
if data.yearRange then
+
builder:wikitext(place and " " or ", ")
builder:wikitext(place and " " or ", ", data.yearRange)
+
local shortDate = data.journal and (data.doi or data.pmid or data.pmc)
 +
if data.date.bib and data.date.hint then
 +
builder:tag("span"):attr("title", data.date.hint):wikitext(data.date.bib)
 +
elseif data.date.bib  then
 +
builder:wikitext(data.date.bib)
 +
elseif data.date.day and shortDate then
 +
builder: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: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(place and ", " or "", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year))
 
elseif data.date.month then
 
elseif data.date.month then
builder:wikitext(", ", resources.months[data.date.month].m, " ", tostring(data.date.year))
+
builder:wikitext(place and ", " or "", resources.months[data.date.month].m, " ", tostring(data.date.year))
 
else
 
else
builder:wikitext(place and " " or ", ", data.year)
+
builder:wikitext(data.date.year)
 
end
 
end
 
builder:wikitext(data.diferentiator or "")
 
builder:wikitext(data.diferentiator or "")
Linia 1161: Linia 1187:
 
 
 
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 1199:
 
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 1240:
 
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
 
needDot = true
 
end
 
end
Linia 1219: Linia 1258:
 
 
 
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.url or data.chapterurl) and data.archive then
builder:wikitext(" [zarchiwizowane z [", escapeUrl(data.url), " adresu]")
+
builder:wikitext(" [zarchiwizowane z [", escapeUrl(data.url or data.chapterurl), " adresu]")
 
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 1255: Linia 1294:
 
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 1309:
 
table.insert(problems, resources.categories.sameJournalAndPublished)
 
table.insert(problems, resources.categories.sameJournalAndPublished)
 
end
 
end
 +
end
 +
 +
if not data.url and not data.chapterurl then
 +
builder:addClass("nourl")
 
end
 
end
 
 
Linia 1296: Linia 1339:
 
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.chapterComma or (data.authorComma == true) or data.editorComma or data.othersComma or data.othersbookvolumeComma 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.authorComma == "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, "url")
 +
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
Linia 1328: Linia 1403:
 
end
 
end
  
local module = {}
+
return {
 +
 +
auto = function(frame)
 +
return Cite(frame:getParent(), nil)
 +
end,
  
module.auto = function(frame)
+
custom = function(frame)
return Cite(frame:getParent(), nil)
+
return Cite(frame, 1)
end
+
end,
  
return module
+
}

Aktualna wersja na dzień 14:10, 20 maj 2018

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

Błąd skryptu: Błąd Lua: Błąd wewnętrzny: Proces interpretera został zakończony z sygnałem "-129".

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

local function softNoWiki(text)
	local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = "&#x22;", ["'"] = "&#x27;", ["["] = "&#x5B;", ["]"] = "&#x5D;", ["{"] = "&#x7B;", ["|"] = "&#x7C;", ["}"] = "&#x7D;"})
	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

	for i, v in ipairs(detector) do
		if detector[i] then
			-- the type is succesfully determined
			-- but in case more than one is possible
			-- use only the first one
			-- include COinS format if this is the only determined type
			return i, count == 1 and resources.COinS[i] or 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 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 = 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
	
	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 result = {}
	local esc1 = string.gsub(author, "\\", "\\\\")
	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 alt = false
	if (splitter == ",") and checkForAltFormat then
		local altAuthors = {}
		alt = true
		for _, 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 _, 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 (separator == ",") then
		check = true
	end
	
	return result, check
end
	
local function formatAuthors(authors, useDecorations, nextgroup)
	local count = #authors
	if count == 0 then
		return nil
	end
	
	local formatter = function(author)
		local a = author:format(nextgroup)
		local r = author.link and ("[["..author.link.."|"..a.."]]") or a
		local s = ""
		if useDecorations then
			for _, v in ipairs(resources.authorFunc) do
				if 	checkPatterns(author, v.prefixes, v.suffixes) then
					s = v.append
					break
				end
			end
		end
	
		return r..s
	end
	
	if count == 1 then
		return formatter(authors[1])
	end
	
	local result = {}
	table.insert(result, formatter(authors[1]))
	
	if count <= 3 then
		table.insert(result, ", ");
		table.insert(result, formatter(authors[2]))
		if count == 3 then
			table.insert(result, ", ");
			table.insert(result, formatter(authors[3]))
		end
		
		return table.concat(result, "")
	end
	
	local title = {}
	for i = 2, count do
		table.insert(title, authors[i]:towiki())
	end
	table.insert(result, "<span class=\"cite-at-al\" title=\"")
	table.insert(result, table.concat(title, ", "))
	table.insert(result, "\"> i inni</span>")
	return table.concat(result, "")
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, "^%[([hH][tT][tT][pP][sS]?://%S*)%s+(.-)%]$")
	if link then
		return description, false, link
	end
	
	return text, false, false
end

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?://.*)$")
	if y then
		return link, y.."-"..m.."-"..d
	end
	
	local y, m, d, link = mw.ustring.match(url, "^https?://webarchive%.nationalarchives%.gov%.uk/(%d%d%d%d)(%d%d)(%d%d)%d%d%d%d%d%d/(https?://.*)$")
	if y then
		return link, y.."-"..m.."-"..d
	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

	-- 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, result.chapterComma = collectAuthors(result.chapterauthor, false)
	result.author, result.authorComma = collectAuthors(result.author, altAuthorParser)
	result.lang = collectLanguages(result.lang)
	result.editor, result.editorComma = collectAuthors(result.editor, false)
	result.others, result.othersComma = 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
			end
			
			result.date = date
			result.patchCitoidDate = patch
		end
	end

	-- fix other dates
	result.accessdate = parseDate(result.accessdate or "", false, false, false)
	if result.accessdate and not result.accessdate.day then
		result.accessdate = nil
	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
				mw.logObject(result.url, "UNUSED URL")
				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]+", " ")
		if mw.ustring.match(journalAbbr, "^[%a%s]+:?[%a%s]+$") then  -- kandydat na skrót powinien mieć tylko litery z opcjonalnymi odstępami i co najwyżej jednym dwukropkiem
			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.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.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.archive = result.chapterurl
			result.chapterurl = al
			if ad then result.archived = ad end
		end
	elseif result.archive and (not (result.url or result.chapterurl) or not result.archived) then
		local al, ad = detectArchive(result.archive)
		if al and not (result.url or result.chapterurl) then result.url = al end
		if ad and not result.archived then result.archived = ad	end
	end

	result.archived = parseDate(result.archived or "", false, false, false)
	if result.archived and not result.archived.day then
		result.archived = null
	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

	-- 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[1] and (authors[1].lastname or authors[1].exact) or "")
		.. (authors[2] and (authors[2].lastname or authors[2].exact) or "")
		.. (authors[3] and (authors[3].lastname or authors[3].exact) or "")
		.. (authors[4] and (authors[4].lastname or authors[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[1].lastname then result["rft.aulast"] = authors[1].lastname end
		if authors[1].name then result["rft.aufirst"] = authors[1].name end
		if authors[1].exact then result["rft.au"] = authors[1].exact end
	end
	if data.date and data.date.coins then
		result["rft.date"] = data.date.coins
	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 COinS(data, coinsFormat)
	if (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 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)
	-- 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("span")
	builder
		:addClass("citation")
		:attr("id", prepareOdnIdentifier(data))
		:wikitext(access.render[data.accessKind], ' ')

	local needDot = false
	local nextAuthorGroup = false
	if data.title then
		
		if data.chapter then
			local authors = data.editor and data.author or data.chapterauthor
			if authors then
				builder:wikitext(formatAuthors(authors, false, nextAuthorGroup), ", ")
				nextAuthorGroup = true
			end
			
			local title = softNoWiki(data.chapter)
			if data.chapterurl then
				builder:wikitext("[", escapeUrl((not data.url and data.archive) 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
			builder:wikitext(formatAuthors(authors, not (editor or false), nextAuthorGroup))
			nextAuthorGroup = true
			if editor then
				builder:wikitext(" (red.)")
			end
			builder:wikitext(", ")
		end
		if customMode and data.authorextra then
			builder:wikitext(data.authorextra, ", ")
		end
	
		local title = softNoWiki(data.title)
		if data.url then
			builder:wikitext("[", escapeUrl(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), "%p$") then
			needDot = true
		end

		local showmediatype = data.mediatype and (#data.mediatype > 0)
		if showmediatype then
			builder:wikitext(" &#x5B;", data.mediatype, "&#x5D;")
			needDot = true
		end

		if not editor and data.editor then
			builder:wikitext(", ", formatAuthors(data.editor, false, true), " (red.)")
		end
		
		if data.others then
			builder:wikitext(", ", formatAuthors(data.others, true, true))
			needDot = true
		end
	end
	
	if data.work then
		builder:wikitext(" [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 " [w:] „" or "„")
		builder:wikitext((data.title or data.work) and ", „" or "„")
		local title = softNoWiki(data.journal)
		if data.journalurl then
			builder:wikitext("[", escapeUrl(data.journalurl), " ", title, "]")
		elseif data.journallink then
			builder:wikitext("[[", data.journallink, "|", title, "]]")
		else
			builder:wikitext(title)
		end
		builder:wikitext("”")
		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.series or data.issue then
		builder:wikitext(" (", data.series or "", (data.series and data.issue) and "; " or "", data.issue or "", ")")
		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
		builder:wikitext(place and " " or ", ")
		local shortDate = data.journal and (data.doi or data.pmid or data.pmc)
		if data.date.bib and data.date.hint then
			builder:tag("span"):attr("title", data.date.hint):wikitext(data.date.bib)
		elseif data.date.bib  then
			builder:wikitext(data.date.bib)
		elseif data.date.day and shortDate then
			builder: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: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(place and ", " or "", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year))
		elseif data.date.month then
			builder:wikitext(place and ", " or "", resources.months[data.date.month].m, " ", tostring(data.date.year))
		else
			builder:wikitext(data.date.year)
		end
		builder:wikitext(data.diferentiator or "")
		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.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.url or data.chapterurl) and data.archive then
		builder:wikitext(" [zarchiwizowane z [", escapeUrl(data.url or data.chapterurl), " adresu]")
		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 needDot then
		builder:wikitext(".")
	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 then
		builder:addClass("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 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.chapterComma or (data.authorComma == true) or data.editorComma or data.othersComma or data.othersbookvolumeComma then
		table.insert(problems, "!!!")
		if addCategories then
			builder:wikitext(resources.categories.suspectedComma)
		end
	end
	if data.authorComma == "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, "url")
		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 #problems > 0 then
		local info = builder:tag("span"):addClass("problemy-w-cytuj")
		if addCategories then
			info:css("display","none")
		else
			info:css("color", "red")
		end
		
		info:wikitext(table.concat(problems,", "))
	end
	
	return builder:done()
end

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

custom = function(frame)
	return Cite(frame, 1)
end,

}