Module:Cytuj
Jump to navigation
Jump to search
local resources = mw.loadData("Module:Cytuj/dane")
local access = mw.loadData("Module:Cytuj/dostęp")
local function softNoWiki(text)
local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = """, ["'"] = "'", ["["] = "[", ["]"] = "]", ["{"] = "{", ["|"] = "|", ["}"] = "}"})
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 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(" ")
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(" ")
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(" ", 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
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 prefix = string.gsub(v.link, "^https?:", "")
if (#address > #prefix) and (string.sub(address, 1, #prefix) == prefix) then
return true
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("Module: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(" [", data.format, "]")
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(" [", data.format, "]")
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(" [", data.mediatype, "]")
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 = " "
builder:addClass("doi"):wikitext(", [[w:pl:DOI (identyfikator cyfrowy)|DOI]]:")
for _, v in ipairs(data.doi) do
builder:wikitext(separator, "[", resources.params.doi.link, 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("Module:ISBN").link(builder, v)
end
needDot = true
end
if data.lccn then
builder:wikitext(", [[w:pl:Biblioteka Kongresu|LCCN]] [", resources.params.lccn.link, mw.uri.encode(data.lccn), " ", data.lccn, "]")
needDot = true
end
if data.issn then
builder:tag("span"):addClass("issn"):wikitext(", [[w:International Standard Serial Number|ISSN]] [", resources.params.issn.link, data.issn, " ", data.issn, "]")
needDot = true
end
if data.pmid then
builder:addClass("pmid"):wikitext(", [[w:PMID|PMID]]: [", resources.params.pmid.link, data.pmid, " ", data.pmid, "]")
needDot = true
end
if data.pmc then
builder:addClass("pmc"):wikitext(", [[w:PMCID|PMCID]]: [", resources.params.pmc.link, data.pmc, "/ PMC", data.pmc, "]")
needDot = true
end
if data.bibcode then
builder:wikitext(", [[w:Bibcode|Bibcode]]: [", resources.params.bibcode.link, data.bibcode, " ", data.bibcode, "]")
needDot = true
end
if data.oclc then
builder:wikitext(", [[w:Online Computer Library Center|OCLC]] [", resources.params.oclc.link, mw.uri.encode(data.oclc), " ", data.oclc, "]")
needDot = true
end
if data.arxiv then
builder:wikitext(", [[w:arXiv|arXiv]]:")
local eprint, class = mw.ustring.match(data.arxiv, "^(%S+)%s+%[([^%[%]]+)%]$")
if eprint then
builder:wikitext("[", resources.params.arxiv.link, eprint, " ", eprint, "] [[//arxiv.org/archive/", class, " ", class, "]]" )
else
builder:wikitext("[", resources.params.arxiv.link, data.arxiv, " ", data.arxiv, "]" )
end
needDot = true
end
if data.jstor then
builder:tag("span"):addClass("jstor"):wikitext(", [[w:JSTOR|JSTOR]]: [", 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(" ")
end
if data.lang then
local languages = require("Module: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,
}