Moduł:Cytuj
Przejdź do nawigacji
Przejdź do wyszukiwania
Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:Cytuj/opis
Błąd skryptu: Błąd Lua: Nie można utworzyć procesu: proc_open(/dev/null): Failed to open stream: Operation not permitted
local resources = mw.loadData("Moduł:Cytuj/dane") local access = mw.loadData("Moduł:Cytuj/dostęp") local function checkUri(uri) local urilen = #uri for _,v in ipairs(resources.supportedUriSchemas) do if (#v < urilen) and (string.lower(string.sub(uri,1, #v)) == v) then return not string.match(uri, '%s') end end end local function softNoWiki(text) local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = """, ["'"] = "'", ["["] = "[", ["]"] = "]", ["{"] = "{", ["|"] = "|", ["}"] = "}"}) -- przywróc [[szablon:J]] z kursywą tak/nie result, count = string.gsub(result, "<span +style="font%-style: ?([a-z]+);?" +lang="([a-z%-]+)" *>", "<span style=\"font-style: %1;\" lang=\"%2\">") -- przywróc [[szablon:J]] goły result, count = string.gsub(result, "<span +lang="([a-z%-]+)" *>", "<span lang=\"%1\">") -- przywróć nowiki result, count = string.gsub(result, "\127'"`UNIQ%-%-(nowiki%-[0-9A-F]+)%-QINU`"'\127", "\127'\"`UNIQ--%1-QINU`\"'\127") return result end local function escapeUrl(url) local result, count = string.gsub(url, "[ '%[%]]", { [" "] = "%20", ["'"] = "%27", ["["] = "%5B", ["]"] = "%5D"}) return result end local function plainText(text) local result, count = string.gsub(text, "</?[Ss][Pp][Aa][Nn][^>]*>", "") return result end local function first(data) return type(data) == "table" and data[1] or data end local function determineMode(p) local detector = {} local count = 0 for i, v in ipairs(resources.modes) do detector[i] = v count = count + 1 end detector[1] = false -- skip 'auto' count = count - 1 for k, v in pairs(resources.params) do local arg = p.args[v.name] for i, w in ipairs(v.used) do if not w and arg then -- unexpected argument if detector[i] then detector[i] = false count = count - 1 if count == 0 then -- the mode cannot be determined break end end end end if count == 0 then -- the mode cannot be determined break end end if count == 1 then for i, v in ipairs(detector) do if detector[i] then return i, resources.COinS[i] end end end if detector[4] -- web? and p.args[resources.params.url.name] then -- promote to web but without COinS return 4, false end for i, v in ipairs(detector) do if detector[i] then -- if type is determined more than once -- use only the first one without COinS return i, false end end -- in case nothing is selected -- use the auto mode as default fallback return 1 end local authorMetatable = {} local authorMethodtable = {} authorMetatable.__index = authorMethodtable local function checkPatterns(author, prefixes, suffixes) if author.exact then return false end if author.prefix and prefixes then for _, v in ipairs(prefixes) do if mw.ustring.match(author.prefix, v) then return true end end end if author.suffix and suffixes then for _, v in ipairs(suffixes) do if mw.ustring.match(author.suffix, v) then return true end end end return false end authorMethodtable.format = function(data, namefirst) if data.exact then return data.exact end if namefirst and data.familynamefirst then namefirst = false end local builder = mw.html.create() local name = data.name and (#data.name > 0) local initials = data.nameinitials and (#data.nameinitials > 0) local namehint = nil if name and initials and (data.name ~= data.nameinitials) then namehint = data.name end if not data.familynamefirst and (name or initials) then local before = namefirst and builder or builder:tag("span"):addClass("cite-name-before") if name then before:tag("span"):addClass("cite-name-full"):wikitext(softNoWiki(data.name)) end if initials then before:tag("span"):css("display", "none"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials)) end before:wikitext(" ") 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 fixInitials(name) local result, _ = mw.ustring.gsub(name, "^(%uh?)%.?%s+(%uh?)%.", "%1.%2.") -- popraw inicjały na początku result, _ = mw.ustring.gsub(result, "%f[%a](%uh?)%.%s+(%uh?)%.", "%1.%2.") -- popraw inicjały w środku result, _ = mw.ustring.gsub(result, "%f[%a](%uh?)%.%s+(%uh?)%.", "%1.%2.") -- popraw kolejne inicjały w środku return result end local function isInQuotes(text) if (string.len(text) < 2) then return false; end local tstart = text:sub(1, 1); if (tstart ~= '"') then return false; end local tend = text:sub(-1); if (tend ~= '"') then return false; end return true; end local function parseAuthor(author) local result = {} if string.match(author, "\127") then -- wpisy z <nowiki> nie są analizowane result.exact = author setmetatable(result, authorMetatable) return result end local author = mw.text.trim(author) local a = string.gsub(author, "\\[\\%.:]", { ["\\\\"]="\\", ["\\."]=",", ["\\:"]=";", }) if a ~= author then result.exact = a setmetatable(result, authorMetatable) return result end if resources.exactAuthors[author] then result.exact = author setmetatable(result, authorMetatable) return result end local exactName = mw.ustring.match(author, "^%s*%*%s*(.*)$") if exactName then result.exact = mw.text.trim(exactName) if #result.exact == 0 then return nil end setmetatable(result, authorMetatable) return result end local prefix0, link, description, suffix0 = mw.ustring.match(author, "^(.-)%[%[(.-)%|(.-)%]%](.*)$") if prefix0 then result.link = link author = description else prefix0, link, suffix0 = mw.ustring.match(author, "^(.-)%[%[(.-)%]%](.*)$") if prefix0 then author = link result.link = link else prefix0 = "" suffix0 = "" end end local prefix1, rest = mw.ustring.match(author, "^([%l%p%s]+)(.+)$") if not prefix1 then rest = author prefix1 = "" end local prefix = mw.text.trim(prefix0.." "..prefix1) if #prefix > 0 then if mw.ustring.sub(prefix, -1) == "#" then result.familynamefirst = true prefix = mw.text.trim(mw.ustring.match(prefix, "^(.-)#$")) end if #prefix > 0 then result.prefix = mw.ustring.gsub(prefix, "%s+", " ") -- collapse spaces end end local rest2, suffix = mw.ustring.match(rest, "^([%w%-%.%s]-)%s([%l%p%s]-)$") if not suffix then rest2 = rest suffix = "" end suffix = mw.text.trim(suffix.." "..suffix0) if #suffix > 0 then result.suffix = mw.ustring.gsub(suffix, "%s+", " ") -- collapse spaces suffix = " "..result.suffix for i, v in ipairs(resources.js) do if mw.ustring.match(suffix, v[1]) then result.suffix = mw.text.trim(mw.ustring.gsub(suffix, v[1], "")) result.js = v[2] break end end else for i, v in ipairs(resources.js) do if mw.ustring.match(rest2, v[1]) then rest2 = mw.text.trim(mw.ustring.gsub(rest2, v[1], "")) result.js = v[2] break end end end local lastname, name = mw.ustring.match(rest2, "%s*([^,]-)%s*,%s*(.-)%s*$") if not lastname then if result.familynamefirst then lastname, name = mw.ustring.match(rest2, "%s*(%u[%l%d%p]*)%s+(.-)%s*$") else local prefix2 name, lastname, prefix2 = mw.ustring.match(rest2, "%s*(.-)%s+((%l[%l%p]%l?)%u[%w%p]-)%s*$") if not resources.lastnamePrefixes[prefix2] then name, lastname = mw.ustring.match(rest2, "%s*(.-)%s+(%u[%w%p]-)%s*$") end end elseif resources.lastnamePrefixes[prefix1] then lastname = prefix1 .. lastname elseif resources.lastnamePrefixes[prefix1] == false then name = name.." "..mw.text.trim(prefix1) end if not lastname then result.lastname = mw.text.trim(rest2) else result.name = fixInitials(name) result.lastname = lastname result.nameinitials = makeInitials(name) end if #result.lastname == 0 then return nil end setmetatable(result, authorMetatable) return result end local function parseDate(date, month, year, patch) local result = {} -- parse full date local y, m, d = false, false, false y, m, d = mw.ustring.match(date, "(%d%d%d%d)[%-%s%./](%d%d?)[%-%s%./](%d%d?)") if y and patch and (date == (y.."-01-01")) then result.year = tonumber(y) result.month = false result.day = false return result, true end if not y then d, m, y = mw.ustring.match(date, "(%d%d?)[%-%s%.](%d%d?)[%-%s%.](%d%d%d%d)") if not y then y, m, d = mw.ustring.match(date, "(%d%d%d%d)%s*(%w+)%s*(%d%d?)") if not y then d, m, y = mw.ustring.match(date, "(%d%d?)%s*(%w+)%s*(%d%d%d%d)") end if m then m = resources.monthparser[mw.ustring.lower(m)] if not m then y = false m = false d = false end end end end if y then y = tonumber(y) m = tonumber(m) d = tonumber(d) end if y and ((d > 31) or (m > 12) or (d < 1) or (m < 1)) then y = false m = false d = false elseif y then result.year = y result.month = m result.day = d return result, false end -- parse year and month y, m = mw.ustring.match(date, "(%d%d%d%d)[%-%s%./](%d%d?)") if not y then m, y = mw.ustring.match(date, "(%d%d?)[%-%s%./](%d%d%d%d)") if not y then y, m = mw.ustring.match(date, "(%d%d%d%d)%s*(%w+)") if not y then m, y = mw.ustring.match(date, "(%w+)%s*(%d%d%d%d)") end if m then m = resources.monthparser[mw.ustring.lower(m)] if not m then y = false m = false end end end end if y then y = tonumber(y) m = tonumber(m) end if y and ((m > 12) or (m < 1)) then y = false m = false elseif y then result.year = y result.month = m return result, false end -- try any method to extract year or month if not y then y = mw.ustring.match(date, "[%s%p%-–]?(%d%d%d%d)[%s%p%-–]?") if y then y = tonumber(y) end if y then result.year = y end end if y then if not m then m = mw.ustring.match(date, "[%s%p%-–]?(%w+)[%s%p%-–]?") if m then m = resources.monthparser[mw.ustring.lower(m)] end if m then result.month = m end end else -- reset only month result.month = nil end if y then return result, false end end local function collectAuthors(author, checkForAltFormat) if not author then return end -- Obsługa cudzysłowów w autorach (treat quoted authors as-is) if (isInQuotes(mw.text.trim(author))) then local strippedAuthor = mw.text.trim(author, '"\t\r\n\f ') return { items = {strippedAuthor}, more=false, comma=false, etal=false, separator="" } end function findUtf8CharAt(text, at) local back = false if at < 0 then at = #text + at + 1 back = true end while at > 1 do local b = string.byte(text, at, at) if (b < 128) or (b >= 192) then break end at = at - 1 end return back and at - #text - 1 or at end local etal = false local authorTail = #author <= 50 and author or string.sub(author, findUtf8CharAt(author, -50)) for i, p in ipairs(resources.etalPatterns) do local a, e = string.match(authorTail, p) if a then author = string.sub(author, 1, #author-#e) etal = e break end end function decodeEntity(s) local result = nil local hex = string.match(s, "^&#[xX]([0-9A-Fa-f]+);$") if hex then result = mw.ustring.char(tonumber(hex, 16)) else local dec = string.match(s, "^&#([0-9]+);$") if dec then result = mw.ustring.char(tonumber(dec, 10)) elseif resources.htmlEntities[s] then result = mw.ustring.char(resources.htmlEntities[s]) else return string.gsub(s, ";", "\\:") end end if result == ";" then return "\\:" elseif result == "," then return "\\." elseif result == "\\" then return "\\\\" else return result end end local authorHead = #author <= 500 and author or string.sub(author, 1, findUtf8CharAt(author, 500) - 1) local result = {} local esc1 = string.gsub(authorHead, "\\", "\\\\") local esc2 = string.gsub(esc1, "&#?[a-zA-Z0-9]+;", decodeEntity) local splitter = string.match(esc2, ";") and ";" or "," local authors = mw.text.split(esc2, splitter.."%s*", false) local nth = false local count = #authors if (#authorHead < #author) and (count > 4) then if count > 5 then table.remove(authors, count) count = count - 1 end local at, _ = string.find(authorHead, authors[count], 1, true) nth = string.sub(author, at) table.remove(authors, count) count = count - 1 end local alt = false if (splitter == ",") and checkForAltFormat then local altAuthors = {} alt = true for i, v in ipairs(authors) do local n0 = "" local s, n = mw.ustring.match(v, "^(%u%l+)%s(%u+)%.?$") if not s then s, n = mw.ustring.match(v, "^(%u%l+[%s%-–]%u%l+)%s(%u+)%.?$") end if not s then n0, s, n = mw.ustring.match(v, "^(%l%l%l?)%s(%u%l+)%s(%u+)%.?$") -- de, von, van, der etc. end if not s then alt = false break end local initials, _ = mw.ustring.gsub(n, "(%u)", "%1.") if #n0 > 0 then n0 = " "..n0 end table.insert(altAuthors, s..", "..initials..n0) end if alt then authors = altAuthors splitter = ";" end end for i, v in ipairs(authors) do local author = parseAuthor(v) if author then table.insert(result, author) end end if #result == 0 then return end local check = false if alt then check = "alt" elseif (#result == 2) and (splitter == ",") then check = not result[1].link and not result[1].exact and not result[1].name or not result[2].link and not result[2].exact and not result[2].name if check then if result[1].lastname and not result[1].name and not result[2].exact and not mw.ustring.match(result[1].lastname, "%S%s+%S") then local oneAuthor = parseAuthor(author) if oneAuthor then table.remove(result,2) result[1] = oneAuthor check = false end end end if check then mw.logObject(result,"przecinek u autora") end end return { items = result, more=nth, comma = check, etal = etal, separator=splitter.." " } end local function formatAuthors(authors, useDecorations, nextgroup, etalForm) local count = #authors.items if count == 0 then return nil, false end local suffix = function(author) if useDecorations then for _, v in ipairs(resources.authorFunc) do if checkPatterns(author, v.prefixes, v.suffixes) then return v.append end end end return "" end local formatter = function(author) local a = author:format(nextgroup) local r = author.link and ("[["..author.link.."|"..a.."]]") or a return r..suffix(author) end if count == 1 then local a1 = formatter(authors.items[1]) local etal = authors.etal and (etalForm or " i inni") or "" return a1..etal, false end local result = {} table.insert(result, formatter(authors.items[1])) if not authors.etal and (count <= 3) then table.insert(result, ", "); table.insert(result, formatter(authors.items[2])) if count == 3 then table.insert(result, ", "); table.insert(result, formatter(authors.items[3])) end return table.concat(result, ""), false end local title = {} for i = 1, count do table.insert(title, authors.items[i]:towiki()..suffix(authors.items[i])) end if authors.more then table.insert(title, authors.more) end table.insert(result, "<span class=\"cite-at-al\" title=\"") table.insert(result, table.concat(title, authors.separator)) if authors.etal then table.insert(result, etalForm or " i inni") end table.insert(result, "\">") table.insert(result, etalForm or " i inni") table.insert(result, "</span>") return table.concat(result, ""), true end local function collectLanguages(value) if value then local result = {} local values = mw.text.split(value, "%s+") for _, v in ipairs(values) do if #v > 0 then table.insert(result, v) end end if #result > 0 then return result end end return nil end local function splitWikiLink(text) local link, description = mw.ustring.match(text, "^%[%[(.-)%|(.-)%]%]$") if link then return description, link, false end local link = mw.ustring.match(text, "^%[%[(.-)%]%]$") if link then return link, link, false end local link, description = mw.ustring.match(text, "^%[(%S*)%s+(.-)%]$") if link and checkUri(link) then return description, false, link end return text, false, false end local function detectArchive(url) local defaultDecoder = resources.archiveDecoders.defaultDecoder for i, v in ipairs(resources.archiveDecoders) do local pattern = type(v) == "string" and v or v.pattern local decoder = type(v) == "table" and v or defaultDecoder local items = { mw.ustring.match(url, pattern) } if #items > 0 then return items[decoder.link], items[decoder.year].."-"..items[decoder.month].."-"..items[decoder.day] end end return false, false end local function isAutoGeneratedUrl(url) local address = string.gsub(url, "^https?:", "") for k, v in pairs(resources.params) do if v.link then local links = type(v.link) == "table" and v.link or { v.link } for _, vlink in ipairs(links) do local prefix = string.gsub(vlink, "^https?:", "") if (#address > #prefix) and (string.sub(address, 1, #prefix) == prefix) then return true end end end end return false end local function loadCitation(frame, mode) local result = {} -- copy parameters for k, v in pairs(resources.params) do if v.used[mode] then local value = frame.args[v.name] if value then value = mw.text.trim(value) if #value > 0 then result[k] = value end end if (v.used[mode] == "!") and not result[k] then -- simulate missing mandatory parameter result[k] = "{{{"..v.name.."}}}" if not result.missing then result.missing = v.name end end end end -- check url argument if result.url == "nie" then result.url = false elseif result.url then if not checkUri(result.url) then local unstrip = mw.text.unstripNoWiki( result.url ) result.url = false if unstrip then result.urlnowiki = checkUri(unstrip) end end end -- translate some parameters local altAuthorParser = false if result.journal and result.pmid and result.author and not result.chapterauthor and not result.editor and not result.others then altAuthorParser = true end result.chapterauthor = collectAuthors(result.chapterauthor, false) result.author = collectAuthors(result.author, altAuthorParser) result.lang = collectLanguages(result.lang) result.editor = collectAuthors(result.editor, false) result.others = collectAuthors(result.others, false) -- parse main bibliographic date if result.date then local bibDate = false local bibDateHint = false local coinsDate = false local odnDate = false for _, v in ipairs(resources.bibDates) do for _, p in ipairs(v.patterns) do local bib, c = mw.ustring.gsub(result.date, p, v.show) if bib and (c > 0) then bibDate = bib bibDateHint = v.hint if v.coins then local cd, cc = mw.ustring.gsub(result.date, p, v.coins) if cd and (cc > 0) then coinsDate = cd end end if v.odn then local od, oc = mw.ustring.gsub(result.date, p, v.odn) if od and (oc > 0) then odnDate = od end end break end if bibDate then break end end end if bibDate then result.date = { bib = bibDate, hint = bibDateHint, coins = coinsDate, odn = odnDate } else local date, patch = parseDate(result.date or "", false, false, true) if date then date.coins = (patch and date.year) or (date.day and string.format("%04d-%02d-%02d", date.year, date.month, date.day)) or (date.month and string.format("%04d-%02d", date.year, date.month)) or date.year date.odn = date.year elseif result.date then result.badDate = true end result.date = date result.patchCitoidDate = patch end end -- fix other dates if result.accessdate then result.accessdate = parseDate(result.accessdate or "", false, false, false) if result.accessdate and not result.accessdate.day then result.badAccessDate = true result.accessdate = nil elseif not result.accessdate then result.badAccessDate = true end end -- allow more ISBN numbers if result.isbn then -- TODO allow "(info)" for custom description followed each identifier result.isbn = mw.text.split(result.isbn, "%s+") end if result.title then local url result.title, result.titlelink, url = splitWikiLink(result.title) if url or result.titlelink then if result.url and (#result.url > 0) and (result.url ~= "{{{url}}}") then result.urlWarning = true end result.url = url end end if result.chapter then result.chapter, result.chapterlink, result.chapterurl = splitWikiLink(result.chapter) end if result.journal then local journalAbbr, _ = mw.ustring.gsub(result.journal, "[%.%s]+", " ") mw.logObject(journalAbbr, "journalAbbr") if mw.ustring.match(journalAbbr, "^[%a%s]+[,:]?[%a%s]+%d?$") -- kandydat na skrót powinien mieć tylko litery z opcjonalnymi odstępami i co najwyżej jednym dwukropkiem lub przecinkiem or mw.ustring.match(journalAbbr, "^[%a%s]+%([%a%s,]+%)$") then -- opcjonalnie jakieś dookreślenie w nawiasie local expandedJournal = mw.loadData("Moduł:Cytuj/czasopisma")[mw.text.trim(journalAbbr)] if expandedJournal then result.originalJournal = result.journal result.journal = expandedJournal end end result.journal, result.journallink, result.journalurl = splitWikiLink(result.journal) end if result.journal and not result.journallink and not result.journalurl and not result.title and result.url then result.journalurl = result.url result.url = false end if result.url and isAutoGeneratedUrl(result.url) then result.rejectedurl = true result.url = false end if result.chapterurl and isAutoGeneratedUrl(result.chapterurl) then result.rejectedurl = true result.chapterurl = false end if result.journalurl and isAutoGeneratedUrl(result.journalurl) then result.rejectedurl = true result.journalurl = false end if not result.archive and result.url then local al, ad = detectArchive(result.url) if al then result.archiveurl = true result.archive = result.url result.url = al if ad then result.archived = ad end end elseif not result.archive and result.chapterurl then local al, ad = detectArchive(result.chapterurl) if al then result.archivechapter = true result.archive = result.chapterurl result.chapterurl = al if ad then result.archived = ad end end elseif not result.archive and result.journalurl then local al, ad = detectArchive(result.journalurl) if al then result.archivejournal = true result.archive = result.journalurl result.journalurl = al if ad then result.archived = ad end end elseif result.archive and not result.archived then local al, ad = detectArchive(result.archive) if ad and not result.archived then result.archived = ad end end if result.archive then if result.chapterurl and not result.url then result.archivechapter = true elseif result.title then result.archiveurl = true elseif result.journal then result.archivejournal = true end end if result.archived then result.archived = parseDate(result.archived or "", false, false, false) if result.archived and not result.archived.day then result.badArchivedDate = true result.archived = null elseif not result.archived then result.badArchivedDate = true end end if result.edition and result.journal and not result.volume and not result.issue then local volume, issue = mw.ustring.match(result.edition, "^%s*([^%(]+)%s+%((.-)%)%s*$"); if volume then result.volume = volume result.issue = issue result.edition = nil end end if result.pmc and (#result.pmc > 3) and (mw.ustring.sub(result.pmc, 1, 3) == "PMC") then result.pmc = mw.ustring.sub(result.pmc, 4, #result.pmc) end if result.accessKind then result.accessKind = access.choice[result.accessKind] result.unknownAccess = not result.accessKind else result.accessKind = (result.pmc and "open") or access.doi[doiPrefix] or access.journals[result.journal] end if result.doi then result.doi = mw.text.split(result.doi, '%s+', false) for i, v in ipairs(result.doi) do local doiPrefix local doiSuffix doiPrefix, doiSuffix = mw.ustring.match(v, "^10%.([^/]+)/(.+)$") if (doiPrefix == "2307") and not result.jstor then result.jstor = doiSuffix end if not result.accessKind and not result.unknownAccess then result.accessKind = access.doi[doiPrefix] end end end if result.patent then mw.logObject(result.patent,"input:patent") local patentPatterns = mw.loadData("Moduł:Brudnopis/Paweł Ziemian/Cytuj/patent") local patent = nil for _, v in ipairs(patentPatterns) do if string.match(result.patent, v.pattern) then local patentNumber, _ = string.gsub(result.patent, v.pattern, v.number or "%1") local patentCountry, _ = string.gsub(result.patent, v.pattern, v.country) local patentInfo = v.info or patentPatterns.ccinfo[patentCountry] if (result.url == nil) and v.url then local url, _ = string.gsub(result.patent, v.pattern, v.url) if checkUri(url) then result.url = url end end local patentTitle if v.title then patentTitle, _ = string.gsub(result.patent, v.pattern, v.title) elseif patentInfo then patentTitle = string.format('<span title="%s">%s %s</span>', patentInfo, patentCountry, patentNumber) else patentTitle = patentCountry.." "..patentNumber end patent = { number = patentNumber, application = v.application, country = patentCountry, title = patentTitle, } break end end result.patent = patent mw.logObject(result.patent,"parsed:patent") end -- return collected parameters if there is any for k, v in pairs(result) do return result end -- there are no supported parameters return nil end local function prepareOdnIdentifier(data) if not data.odn or (#data.odn == 0) or (data.odn == "nie") then return nil end data.diferentiator = mw.ustring.match(data.odn, "^([a-z])$") or false if data.odn ~= "tak" and not data.diferentiator then -- TODO return only CITEREF... return data.odn end local authors = data.chapterauthor or data.author or data.editor if not authors then -- required custom identifier return nil end return "CITEREF" .. (authors.items[1] and (authors.items[1].lastname or authors.items[1].exact) or "") .. (authors.items[2] and (authors.items[2].lastname or authors.items[2].exact) or "") .. (authors.items[3] and (authors.items[3].lastname or authors.items[3].exact) or "") .. (authors.items[4] and (authors.items[4].lastname or authors.items[4].exact) or "") .. (data.date and data.date.odn or "") .. (data.diferentiator or "") end local function bookCOinS(data) local authors = data.chapterauthor or data.author local result = {} result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:book" if data.chapter and (#data.chapter > 0) then result["rft.gengre"] = "bookitem" result["rft.atitle"] = plainText(data.chapter) result["rft.btitle"] = plainText(data.title) elseif data.work and (#data.work > 0) then result["rft.gengre"] = "bookitem" result["rft.atitle"] = plainText(data.title) result["rft.btitle"] = plainText(data.work) else result["rft.btitle"] = plainText(data.title) result["rft.gengre"] = "book" end if authors then if authors.items[1].lastname then result["rft.aulast"] = authors.items[1].lastname end if authors.items[1].name then result["rft.aufirst"] = authors.items[1].name end if authors.items[1].exact then result["rft.au"] = authors.items[1].exact end end if data.date and data.date.coins then result["rft.date"] = data.date.coins end if data.series then result["rft.series"] = data.series end if data.edition then result["rft.edition"] = data.edition end if data.publisher then result["rft.pub"] = data.publisher end if data.place then result["rft.place"] = data.place end if data.pages then result["rft.pages"] = data.pages end if data.isbn then result["rft.isbn"] = data.isbn[1] end if data.issn then result["rft.issn"] = data.issn end local params = { "ctx_ver=Z39.88-2004", mw.uri.buildQueryString(result), } if data.oclc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:oclcnum/"..data.oclc})) end if data.doi then for _, v in ipairs(data.doi) do table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..v})) end end if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end if data.lccn then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:lccn/"..data.lccn})) end local coinsData = table.concat(params, "&") return coinsData; end local function journalCOinS(data) local result = {} result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal" local gengre = (data.arxiv and (#data.arxiv > 0)) and "preprint" or "article" result["rft.gengre"] = data.title and gengre or "journal" if data.title then result["rft.atitle"] = plainText(data.title) end result["rft.jtitle"] = plainText(data.journal) if data.chapter then result["rft.atitle"] = plainText(data.chapter) end if data.date and data.date.coins then result["rft.date"] = data.date.coins end if data.title and author then if author[1].lastname then result["rft.aulast"] = author[1].lastname end if author[1].name then result["rft.aufirst"] = author[1].name end if author[1].exact then result["rft.au"] = author[1].exact end end if data.volume then result["rft.volume"] = data.volume end if data.issue then result["rft.edition"] = data.issue end if data.publisher then result["rft.pub"] = data.publisher end if data.place then result["rft.place"] = data.place end if data.pages then result["rft.pages"] = data.pages end if data.issn then result["rft.issn"] = data.issn end local params = { "ctx_ver=Z39.88-2004", mw.uri.buildQueryString(result), } if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end if data.pmc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmc/"..data.pmc})) end if data.doi then for _, v in ipairs(data.doi) do table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..v})) end end if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end local coinsData = table.concat(params, "&") return coinsData; end local function webCOinS(data) local result = {} result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal" result["rft.gengre"] = "unknown" if data.title then result["rft.atitle"] = plainText(data.title) end result["rft.jtitle"] = plainText(data.published) if data.date and data.date.coins then result["rft.date"] = data.date.coins end if data.title and author then if author[1].lastname then result["rft.aulast"] = author[1].lastname end if author[1].name then result["rft.aufirst"] = author[1].name end if author[1].exact then result["rft.au"] = author[1].exact end end local params = { "ctx_ver=Z39.88-2004", mw.uri.buildQueryString(result), } if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end local coinsData = table.concat(params, "&") return coinsData; end local function patentCOinS(data) local result = {} result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal" if data.title then result["rft.title"] = plainText(data.title) end result[data.patent.application and "rft.applnumber" or "rft.number"] = data.patent.number result["rft.cc"] = data.patent.country if data.date and data.date.coins then result[data.patent.application and "rft.appldate" or "rft.date"] = data.date.coins end if author then if author[1].lastname then result["rft.aulast"] = author[1].lastname end if author[1].name then result["rft.aufirst"] = author[1].name end if author[1].exact then result["rft.au"] = author[1].exact end end -- rft.assignee = author (wszyscy?) -- rft.inventor = others (wszyscy?) local params = { "ctx_ver=Z39.88-2004", mw.uri.buildQueryString(result), } if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end local coinsData = table.concat(params, "&") return coinsData; end local function COinS(data, coinsFormat) if resources.abbrTitles[data.title] then -- full citation is elsewhere return false elseif (coinsFormat == "info:ofi/fmt:kev:mtx:book") and data.title and (#data.title > 0) then -- title is mandatory element for books return bookCOinS(data) elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.journal and (#data.journal > 0) and (not data.published or (data.journal ~= data.published)) then -- journal title is mandatory element for journals return journalCOinS(data) elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.published and (#data.published > 0) then return webCOinS(data) elseif coinsFormat == "info:ofi/fmt:kev:mtx:patent" and data.patent then return patentCOinS(data) elseif data.title and (#data.title > 0) then -- treat web or unrecognized citations as book return bookCOinS(data) else return false end end local function Cite(p, mode, appendText) -- debug helper if p.args[3] then mw.log(p.args[3]) end local customMode = mode -- try to determine type basing on passed parameters local coinsFormat = resources.COinS[mode] if not mode then mode, coinsFormat = determineMode(p) end local data = loadCitation(p, mode) if not data then return resources.categories.empty end if data.missing then -- do not produce any COiNS info -- if some mandatory argument is missing coinsFormat = false end local builder = mw.html.create("cite") builder :addClass("citation") :addClass(resources.cite[mode] or nil) :addClass(access.class[data.accessKind]) :attr("id", prepareOdnIdentifier(data)) --:wikitext(access.render[data.accessKind], ' ') local needDot = false local nextAuthorGroup = false if data.title or data.patent then if data.chapter then local authors = data.editor and data.author or data.chapterauthor if authors then local list, etal = formatAuthors(authors, false, nextAuthorGroup, nil) builder:wikitext(list, ", ") nextAuthorGroup = true end local title = softNoWiki(data.chapter) if data.chapterurl then builder:wikitext("[", escapeUrl(data.archivechapter and data.archive or data.chapterurl), " ''", title, "'']") elseif data.chapterlink then builder:wikitext("[[", data.chapterlink, "|''", title, "'']]") else builder:wikitext("''", title, "''") end if data.format then builder:wikitext(" [", 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 local list, etal = formatAuthors(authors, not (editor or false), nextAuthorGroup, editor and " i inni red." or nil) builder:wikitext(list) nextAuthorGroup = true if editor and not etal and not authors.etal then builder:wikitext(" (red.)") end builder:wikitext(", ") end if customMode and data.authorextra then builder:wikitext(data.authorextra, ", ") end if resources.abbrTitles[data.title] then local title = resources.abbrTitles[data.title] builder:wikitext(title) needDot = not mw.ustring.match(title, "%.%]%]$") and not mw.ustring.match(title, "%.$") elseif data.title then local title = softNoWiki(data.title) if data.url or data.archiveurl then builder:wikitext("[", escapeUrl(data.archiveurl and data.archive or data.url), " ''", title, "'']") elseif data.titlelink then builder:wikitext("[[", data.titlelink, "|''", title, "'']]") else builder:wikitext("''", title, "''") end if not data.chapter and data.format then builder:wikitext(" [", data.format, "]") needDot = true elseif not mw.ustring.match(plainText(title), "[%.,!?]$") then needDot = true end local showmediatype = data.mediatype and (#data.mediatype > 0) if showmediatype then builder:wikitext(" [", data.mediatype, "]") needDot = true end end if not editor and data.editor then local list, etal = formatAuthors(data.editor, false, true, " i inni red.") builder:wikitext(needDot and ", " or " ", list, (etal or data.editor.etal) and "" or " (red.)") needDot = true end if data.others then local list, etal = formatAuthors(data.others, true, true, nil) builder:wikitext(needDot and ", " or " ", data.patent and resources.patent.inventor.." " or "", list) needDot = true end if data.patent then local title = (not data.title and data.url) and string.format("[%s %s]", escapeUrl(data.url), data.patent.title) or data.patent.title builder:wikitext(needDot and ", " or " ", resources.patent[data.patent.application], " ", title) needDot = true end elseif data.journal and data.author then local list, etal = formatAuthors(data.author, false, false, nil) builder:wikitext(list, ", ") end if data.work then builder:wikitext((data.title or data.patent) and ", " or "", "[w:] ", data.work, (not data.mediatype and data.url) and " [online]" or "") needDot = true end if data.journal and (not data.published or (data.journal ~= data.published)) then builder:wikitext((data.title or data.work) and ", " or "") local title = softNoWiki(data.journal) if data.journalurl or data.archivejournal then builder:wikitext("[", escapeUrl(data.archivejournal and data.archive or data.journalurl), " „", title, "”]") elseif data.journallink then builder:wikitext("„[[", data.journallink, "|", title, "]]”") else builder:wikitext("„", title, "”") end needDot = true end if data.responsibility then builder:wikitext(", ", data.responsibility) needDot = true end if data.edition then builder:wikitext(data.journal and ", " or ", wyd. ", data.edition) needDot = true end if data.volume then builder:wikitext(data.journal and ", " or ", t. ", data.volume) needDot = true end if data.journal and data.issue then builder:wikitext(" (", data.issue, ")") needDot = true end if data.description and (#data.description > 0) then builder:wikitext(", ", data.description) needDot = true end if data.published and not data.publisher then builder:wikitext(", ", data.published) needDot = true end local place = false if data.place then builder:wikitext(", ", data.place) needDot = true place = true end if data.publisher then builder:wikitext(place and ": " or ", ", data.publisher) needDot = true place = false end if data.date then local shortDate = data.journal and (data.doi or data.pmid or data.pmc) if data.date.bib and data.date.hint then builder:wikitext(place and " " or ", "):tag("span"):attr("title", data.date.hint):wikitext(data.date.bib) elseif data.date.bib then builder:wikitext(place and " " or ", ", data.date.bib) elseif data.date.day and shortDate then builder:wikitext(place and " " or ", "):tag("span"):attr("title", tostring(data.date.day).." "..resources.months[data.date.month].d.." "..tostring(data.date.year)):wikitext(data.date.year) elseif data.date.month and shortDate then builder:wikitext(place and " " or ", "):tag("span"):attr("title", resources.months[data.date.month].m.." "..tostring(data.date.year)):wikitext(data.date.year) elseif data.date.day then builder:wikitext(", ", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year)) elseif data.date.month then builder:wikitext(", ", resources.months[data.date.month].m, " ", tostring(data.date.year)) else builder:wikitext(place and " " or ", ", data.date.year) end builder:wikitext(data.diferentiator or "") needDot = true end if not data.journal and (data.series or data.issue) then builder:wikitext(" (", data.series or "", (data.series and data.issue) and "; " or "", data.issue or "", ")") needDot = true elseif data.journal and data.series then builder:wikitext(" (", data.series, ")") needDot = true end if data.p and #data.p > 0 then local isNonStandardPageNumber = mw.ustring.match(data.p, "[^%s0-9,%-–]") builder:wikitext(isNonStandardPageNumber and ", " or ", s. ", data.p) needDot = true end if data.doi then local separator = " " 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]]: [", first(resources.params.pmid.link), data.pmid, " ", data.pmid, "]") needDot = true end if data.pmc then builder:addClass("pmc"):wikitext(", [[PMCID]]: [", first(resources.params.pmc.link), data.pmc, "/ PMC", data.pmc, "]") needDot = true end if data.bibcode then builder:wikitext(", [[Bibcode]]: [", first(resources.params.bibcode.link), data.bibcode, " ", data.bibcode, "]") needDot = true end if data.oclc then builder:wikitext(", [[Online Computer Library Center|OCLC]] [", 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, "] [[//arxiv.org/archive/", class, " ", class, "]]" ) 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]]: [", first(resources.params.jstor.link), data.jstor, " ", data.jstor, "]") needDot = true end if data.ol then builder:tag("span"):addClass("open-library"):wikitext(", [[Open Library|OL]]: [", first(resources.params.ol.link), data.ol, " ", data.ol, "]") needDot = true end if data.id then builder:wikitext(", ", data.id) needDot = true end if data.accessdate then builder:tag("span"):addClass("accessdate"):wikitext(" [dostęp ", string.format("%04d-%02d-%02d", data.accessdate.year, data.accessdate.month, data.accessdate.day), "]") needDot = true end if data.archive then builder:wikitext(" [zarchiwizowane") local url = data.archiveurl and data.url or (data.archivechapter and data.chapterurl or data.journalurl) if url then builder:wikitext(" z [", escapeUrl(url), " adresu]") end if data.archived and data.archived.day then builder:wikitext(" ", string.format("%04d-%02d-%02d", data.archived.year, data.archived.month, data.archived.day)) end builder:wikitext("]") needDot = true end if data.quotation then builder:wikitext(", Cytat: ", data.quotation) needDot = true end local coinsData = COinS(data, coinsFormat) if coinsData then builder:tag("span"):addClass("Z3988"):attr("title",coinsData):css("display","none"):wikitext(" ") end if data.lang then local languages = require("Moduł:Lang").lang({args = data.lang}) builder:wikitext(" ", languages) needDot = true end if data.fullStop then if not mw.ustring.match(data.fullStop, "^[%.!?,;:]") then builder:wikitext(", ") end builder:wikitext(data.fullStop) needDot = mw.ustring.match(data.fullStop, "[%.!?,;:]$") == nil end if needDot then builder:wikitext(".") end if appendText then builder:wikitext(appendText) end -- categories local addCategories = mw.title.getCurrentTitle().namespace == 0 local problems = {} if not customMode and (mode == 1) then builder:wikitext(resources.categories.undetermined) table.insert(problems, "???") end if data.publisher and data.published then table.insert(problems, "p?") if addCategories then table.insert(problems, resources.categories.unusedPublished) end end if data.journal and data.published and (data.journal == data.published) then table.insert(problems, "j?") if addCategories then table.insert(problems, resources.categories.sameJournalAndPublished) end end if (not data.url and not data.chapterurl) or (not data.title and not data.journalurl) then builder:addClass(data.urlnowiki and "urlnowiki" or "nourl") end local missing = false local needurl = ((resources.params.published.used[mode] == "*") and data.published) or (resources.params.url.used[mode] == "*") if data.missing then -- usually missing title, this is the first check for mandatory arguments table.insert(problems, data.missing) missing = true elseif needurl and not data.url and not data.chapterurl and not data.arxiv and not data.archive then -- build in support for missing external link for page citation table.insert(problems, resources.params.url.name) missing = true else -- any other missing value (first catch) for k, v in pairs(resources.params) do if (v.used[mode] == "!") and (not data[k] or (#data[k] == 0)) then table.insert(problems, v.name) missing = true break end end end if missing and addCategories then builder:wikitext(string.format(resources.categories.missingArg, resources.modes[mode])) end if (data.chapterauthor and data.chapterauthor.comma) or (data.author and (data.author.comma == true)) or (data.editor and data.editor.comma) or (data.others and data.others.comma) then table.insert(problems, "!!!") if addCategories then builder:wikitext(resources.categories.suspectedComma) end end if data.author and (data.author.comma == "alt") then table.insert(problems, "a?") if addCategories then builder:wikitext(resources.categories.altAuthor) end end if data.originalJournal then table.insert(problems, "c?") if addCategories then builder:wikitext(resources.categories.altJournal) end end local citewiki = (data.journal and mw.ustring.match(data.journal, "[Ww]ikipedia")) or (data.publisher and mw.ustring.match(data.publisher, "[Ww]ikipedia")) or (data.published and mw.ustring.match(data.published, "[Ww]ikipedia")) or (data.url and mw.ustring.match(data.url, "%.wikipedia%.org")) if citewiki then table.insert(problems, "wiki?") if addCategories then builder:wikitext(resources.categories.wiki) end end if data.unknownAccess then table.insert(problems, "dostęp?") if addCategories then builder:wikitext(resources.categories.unknownAccess) end end if data.rejectedurl then table.insert(problems, "<s>url</s>") if addCategories then builder:wikitext(resources.categories.rejectedUrl) end end if data.urlWarning then table.insert(problems, "Url") if addCategories then builder:wikitext(resources.categories.unusedUrl) end end if data.patchCitoidDate then table.insert(problems, "1 stycznia") end if data.badDate then table.insert(problems, "data?") end if data.badAccessDate then table.insert(problems, "data dostępu?") end if data.badArchivedDate then table.insert(problems, "zarchiwizowano?") end if addCategories and (data.badDate or data.badAccessDate or data.badArchiveDate) then builder:wikitext(resources.categories.badDate) end if (data.author and data.author.etal) or (data.chapterauthor and data.chapterauthor.etal) or (data.editor and data.editor.etal) or (data.others and data.others.etal) then table.insert(problems, "i inni") if addCategories then builder:wikitext(resources.categories.etal) end end if #problems > 0 then local info = builder:tag("span") :addClass("problemy") :addClass("problemy-w-cytuj") :attr("aria-hidden", "true") :attr("data-nosnippet", "") info:wikitext(table.concat(problems,", ")) end return builder:done() end return { auto = function(frame) return Cite(frame:getParent(), nil, nil) end, custom = function(frame) local traceCategory = false local pagename = mw.title.getCurrentTitle() if (pagename.namespace == 10) and frame.getParent then local template = mw.title.new( frame:getParent():getTitle(), "Szablon" ) if mw.title.compare(template, pagename) == 0 then traceCategory = resources.categories.traceInvokeCustom end end local customMode = frame.args[1] local mode = 1 if customMode then customMode = mw.text.trim(customMode) for i, v in ipairs(resources.modes) do if customMode == v then mode = i break end end end return Cite(frame, mode, traceCategory) end, }