Module:Citation
Jump to navigation
Jump to search
This module depends on the following other modules: |
Implements {{citation}}.
require('strict')
local p = {}
local getArgs = require('Module:Arguments').getArgs
local ISBN = require('Module:ISBN')._ISBN
local function nowiki(text)
return mw.getCurrentFrame():callParserFunction('#tag', {'nowiki', text})
end
local function citation_id(args)
if args.ref then
if args.ref ~= 'none' then
return mw.uri.anchorEncode(args.ref)
end
else
local surnames = {}
for i = 1, #args['author_data'] do
if args['author_data'][i]['surname'] then
table.insert(surnames, args['author_data'][i]['surname'])
end
end
if #surnames == 0 then
for i = 1, #args['editor_data'] do
if args['editor_data'][i]['surname'] then
table.insert(surnames, args['editor_data'][i]['surname'])
end
end
end
return mw.uri.anchorEncode('CITEREF' .. table.concat(surnames) .. (args.year or ''))
end
end
local function citation_authors(args)
local authors = {}
for i = 1, #args['author_data'] do
local text
if args.swapall ~= false then
text = args['author_data'][i]['surname']
if args['author_data'][i]['given'] then
if text then
text = text .. ', '
else
text = ''
end
text = text .. args['author_data'][i]['given']
end
else
text = args['author_data'][i]['given']
if args['author_data'][i]['surname'] then
if text then
text = text .. ' '
else
text = ''
end
text = text .. args['author_data'][i]['surname']
end
end
local link
if args['author_data'][i]['link'] then
link = '[[' .. args['author_data'][i]['link'] .. '|' .. (text or '') .. ']]'
else
link = text
end
if link then
table.insert(authors, link)
end
end
local text
if #authors > 3 then
text = authors[1] .. '; ' .. authors[2] .. ' & ' .. authors[3] .. ' et al.'
elseif #authors > 1 then
text = table.concat(authors, '; ', 1, #authors - 1) .. ' & ' .. authors[#authors]
elseif authors[1] then
text = authors[1]
end
return text
end
local function citation_patent(args)
args.publicationnumber = args.publicationnumber or args.patentnumber
local cite = mw.html.create('cite')
:css({['font-style'] = 'normal'})
:attr('id', citation_id(args))
-- text
local citation_text = {}
args.swapall = false
local authors = citation_authors(args)
if authors then
if args['date'] then
text = text .. ' (' .. args['date'] .. ')'
end
table.insert(citation_text, authors)
end
if args.title then
table.insert(citation_text, '"' .. args.title .. '"')
end
local citation_link = '[https://v3.espacenet.com/textdoc?DB=EPODOC&IDX=' .. (args.countrycode or '') .. (args.publicationnumber or '') .. ' ' .. (args.countrycode or '')
if args.description then
citation_link = citation_link .. ' ' .. args.description
end
if args.publicationnumber then
citation_link = citation_link .. ' ' .. args.publicationnumber
end
citation_link = citation_link .. ']'
table.insert(citation_text, citation_link)
if args.publicationdate then
table.insert(citation_text, 'published in ' .. args.publicationdate)
end
if args.issuedate then
table.insert(citation_text, 'issued ' .. args.issuedate)
end
if args.filingdate then
table.insert(citation_text, 'filed ' .. args.filingdate)
end
if #citation_text > 0 then
citation_text[#citation_text] = citation_text[#citation_text] .. '.'
end
cite:wikitext(table.concat(citation_text, ', '))
return tostring(cite)
end
local function work_link(args)
local link_display
if args.title then
local link
if args.url then
link = args.url
elseif args.doi then
link = 'https://doi.org/' .. mw.uri.encode(args.doi)
elseif args.pmid then
link = 'https://www.ncbi.nlm.nih.gov/pubmed/' .. mw.uri.encode(args.pmid)
end
if link then
link_display = '[' .. link .. ' ' .. args.title .. ']'
else
link_display = args.title
end
if args.italics then
link_display = "''" .. link_display .. "''"
else
link_display = '"' .. link_display .. '"'
end
end
return link_display
end
local function citation_core(args)
args.periodical = args.periodical or args.journal or args.newspaper or args.magazine
args.includedworktitle = args.chapter or args.contribution or args.includedworktitle
args.includedworkurl = args.chapterurl or args.contributionurl or args.includedworkurl or args.url
args.place = args.place or args.location
args.publicationplace = args.publicationplace or args.place
if args.periodical then
args.at = args.pages or args.page or args.at
elseif args.page then
args.at = 'p. ' .. args.page
elseif args.pages then
args.at = 'pp. ' .. args.pages
end
local cite = mw.html.create('cite')
:css({['font-style'] = 'normal'})
:attr('id', citation_id(args))
local citation_text = {}
-- author or editor and date
local authors = citation_authors(args)
local editors = citation_authors({['author_data'] = args['editor_data']})
if authors or editors then
local authed_text
if authors then
authed_text = authors
elseif #args['editor_data'] > 1 then
authed_text = editors .. ', eds.'
else
authed_text = editors .. ', ed.'
end
if args['date'] then
authed_text = authed_text .. ' (' .. args['date'] .. ')'
end
table.insert(citation_text, authed_text)
end
-- title of included work
local title = work_link({
['title'] = args.includedworktitle,
['url'] = args.includedworkurl,
['doi'] = args.doi,
['pmid'] = args.pmid,
['italics'] = (args.periodical ~= nil)
})
if title then
table.insert(citation_text, title)
end
-- place (if different than publicationplace)
if args.place and (args.place ~= args.publicationplace) then
table.insert(citation_text, 'written at ' .. args.place)
end
-- editor of compilation
if editors and authors then
local editor_text = editors
if args.includedworktitle then
editor_text = 'in ' .. editor_text
elseif #args['editor_data'] > 1 then
editor_text = editor_text .. ', eds.'
else
editor_text = editor_text .. ', ed.'
end
table.insert(citation_text, editor_text)
end
-- periodicals
if args.periodical then
local periodical_title = work_link({
['title'] = args.title,
['url'] = args.url,
['doi'] = args.doi,
['pmid'] = args.pmid,
['italics'] = false
})
if periodical_title then
table.insert(citation_text, periodical_title)
end
table.insert(citation_text, "''" .. args.periodical .. "''")
local info = {}
if args.series then
table.insert(info, args.series)
end
local pub = {}
if args.publicationplace then
table.insert(pub, args.publicationplace)
end
if args.publisher then
table.insert(pub, args.publisher)
end
if #pub > 0 then
table.insert(info, '(' .. table.concat(pub, ': ') .. ')')
end
if args.volume and args.issue then
table.insert(info, "'''" .. args.volume .. "''' (" .. args.issue .. ')')
elseif args.volume then
table.insert(info, "'''" .. args.volume .. "'''")
elseif args.issue then
table.insert(info, '(no. ' .. args.issue .. ')')
end
if args.at and #info > 0 then
info[#info] = info[#info] .. ': ' .. args.at
elseif args.at then
table.insert(info, ': ' .. args.at)
end
if #info > 0 then
table.insert(citation_text, table.concat(info, ' '))
end
-- anything else with a title, including books
else
local work_title = work_link({
['title'] = args.title,
['url'] = args.url,
['doi'] = args.doi,
['pmid'] = args.pmid,
['italics'] = true
})
if work_title then
table.insert(citation_text, work_title)
end
local voled = {}
if args.volume then
table.insert(voled, 'vol. ' .. args.volume)
end
if args.edition then
table.insert(voled, '(' .. args.edition .. ' ed.)')
end
if #voled > 0 then
table.insert(citation_text, table.concat(voled, ' '))
end
if args.series then
table.insert(citation_text, args.series)
end
local pub = {}
if args.publicationplace then
table.insert(pub, args.publicationplace)
end
if args.publisher then
table.insert(pub, args.publisher)
end
if #pub > 0 then
table.insert(citation_text, table.concat(pub, ': '))
end
end
-- date (if no author/editor)
if not authors and not editors and args['date'] then
table.insert(citation_text, args['date'])
end
-- publication date
if args.publicationdate and args.publicationdate ~= args['date'] then
if (editors and authors) or (not editors and args.periodical) then
table.insert(citation_text, args.publicationdate)
elseif #citation_text > 0 then
citation_text[#citation_text] = citation_text[#citation_text] .. ' (published ' .. args.publicationdate .. ')'
else
table.insert(citation_text, '(published ' .. args.publicationdate .. ')')
end
end
-- page within included work
if not args.periodical and args.at then
table.insert(citation_text, args.at)
end
-- misc. identifier
if args.id then
table.insert(citation_text, args.id)
end
-- ISBN
if args.isbn then
table.insert(citation_text, ISBN({args.isbn}))
end
-- ISSN
if args.issn then
table.insert(
citation_text,
'[[:d:Special:GoToLinkedPage/enwiki/Q131276|ISSN]] [https://worldcat.org/issn/' .. mw.uri.encode(args.issn) .. ' ' .. nowiki(args.issn) .. ']'
)
end
-- OCLC
if args.oclc then
table.insert(
citation_text,
'[[:d:Special:GoToLinkedPage/enwiki/Q190593|OCLC]] [https://worldcat.org/oclc/' .. mw.uri.encode(args.oclc) .. ' ' .. nowiki(args.oclc) .. ']'
)
end
-- PMID
if args.pmid then
table.insert(citation_text, '[[pmid:' .. args.pmid .. ']]')
end
-- DOI
if args.doi then
if args.includedworkurl then
table.insert(
citation_text,
'[[:d:Special:GoToLinkedPage/enwiki/Q25670|doi]]:[https://doi.org/' .. mw.uri.encode(args.doi) .. ' ' .. nowiki(args.doi) .. ']'
)
elseif #citation_text > 0 then
citation_text[#citation_text] = citation_text[#citation_text] .. '<span class="printonly">, DOI ' .. nowiki(args.doi) .. '</span>'
else
table.insert(citation_text, '<span class="printonly">DOI ' .. nowiki(args.doi) .. '</span>')
end
end
-- URL and accessdate
if args.includedworkurl then
local accessdate = ''
if args.accessdate then
accessdate = '. Retrieved on ' .. args.accessdate
end
if args.includedworktitle or args.title then
-- local bracketed_link = '<[' .. args.includedworkurl .. ' ' .. args.includedworkurl .. ']>'
local bracketed_link = '<' .. args.includedworkurl .. '>'
if #citation_text > 0 then
citation_text[#citation_text] = citation_text[#citation_text] .. '<span class="printonly">, ' .. bracketed_link .. '</span>' .. accessdate
else
table.insert(citation_text, '<span class="printonly">' .. bracketed_link .. '</span>' .. accessdate)
end
else
table.insert(citation_text, bracketed_link .. accessdate)
end
end
if #citation_text > 0 then
citation_text[#citation_text] = citation_text[#citation_text] .. '.'
end
cite:wikitext(table.concat(citation_text, ', '))
-- This is a COinS tag (http://ocoins.info), which allows automated tools to parse the citation information.
local coins = mw.html.create('span')
:addClass('Z3988')
local coins_title = {'ctx_ver=Z39.88-2004&rft_val_fmt=' .. mw.uri.encode('info:ofi/fmt:kev:mtx:') .. 'book'}
if args.periodical then
table.insert(
coins_title,
'&rft.genre=article&rft.atitle=' .. mw.uri.encode(args.title or '') .. '&rft.title=' .. mw.uri.encode(args.periodical or '')
)
elseif args.includedworktitle then
table.insert(
coins_title,
'&rft.genre=bookitem&rft.atitle=' .. mw.uri.encode(args.includedworktitle)
)
else
table.insert(coins_title, '&rft.genre=book')
end
table.insert(coins_title, '&rft.title=' .. mw.uri.encode(args.title or ''))
if args['author_data'][1]['surname'] then
table.insert(coins_title, '&rft.aulast=' .. mw.uri.encode(args['author_data'][1]['surname']))
end
if args['author_data'][1]['given'] then
table.insert(coins_title, '&rft.aufirst=' .. mw.uri.encode(args['author_data'][1]['given']))
end
local coins_fragments = {
['at'] = '&rft.pages=',
['publicationplace'] = '&rft.place=',
['publisher'] = '&rft.pub=',
['doi'] = '&rft_id=info:doi/',
['pmid'] = '&rft_id=info:pmid/',
['includedworkurl'] = '&rft_id='
}
for k, v in pairs({'date', 'volume', 'issue', 'at', 'edition', 'place', 'publicationplace', 'publisher', 'doi', 'pmid', 'isbn', 'issn', 'includedworkurl'}) do
if args[v] then
table.insert(
coins_title,
(coins_fragments[v] or '&rft.' .. v .. '=') .. mw.uri.encode(args[v])
)
end
end
coins:attr('title', table.concat(coins_title))
coins:wikitext('<span style="display:none;"> </span>')
return tostring(cite) .. tostring(coins)
end
function p._citation(args)
-- lowercase args and remove hyphens
local alias_args = {}
for k, v in pairs(args) do
local newk = string.gsub(string.lower(k), '-', '')
mw.logObject(k .. ' to ' .. newk)
alias_args[newk] = v
end
for k, v in pairs(alias_args) do
args[k] = args[k] or v
end
-- date
args['date'] = args['date'] or args['year'] or args.publicationdate
-- accessdate
-- FIXME: use Lua
if args.accessdate then
args.accessdate = mw.getContentLanguage():formatDate('F j, Y', args.accessdate, true)
end
-- year
if not args.year then
if args['date'] then
-- FIXME: use Lua
local success, datevalue = pcall(function()
return mw.getContentLanguage():formatDate('Y', args['date'], true)
end)
if success then
args['year'] = datevalue
end
end
if args.publicationdate then
-- FIXME: use Lua
local success, datevalue = pcall(function()
return mw.getContentLanguage():formatDate('Y', args.publicationdate, true)
end)
if success then
args['year'] = datevalue
end
end
end
if not args.year then
args.year = args['date']
end
-- inventor to author
alias_args = {}
local patent = false
for k, v in pairs(args) do
if mw.ustring.len(k) >= 8 and mw.ustring.sub(k, 1, 8) == 'inventor' then
local akey = 'author' .. mw.ustring.sub(k, 9)
alias_args[akey] = v
patent = true
end
end
for k, v in pairs(alias_args) do
args[k] = args[k] or v
end
-- organize author and editor info
local author_data = {}
local editor_data = {}
for k, v in pairs(args) do
local b, n, a = mw.ustring.match(k, '(%l*)(%d*)(%l*)')
n = tonumber(n)
--[=[
mw.logObject('b: ' .. (b or ''))
mw.logObject('n: ' .. (n or ''))
mw.logObject('a: ' .. (a or ''))
]=]
if n then
if b == 'author' or b == 'surname' or b == 'last' or b == 'given' or b == 'first' or b == 'authorlink' then
author_data[n] = author_data[n] or {}
if b == 'surname' or b == 'last' then
author_data[n]['surname'] = author_data[n]['surname'] or v
elseif b == 'given' or b == 'first' then
author_data[n]['given'] = author_data[n]['given'] or v
elseif b == 'authorlink' then
author_data[n]['link'] = author_data[n]['link'] or v
else
if a == 'surname' or a == 'last' then
author_data[n]['surname'] = author_data[n]['surname'] or v
elseif a == 'given' or a == 'first' then
author_data[n]['given'] = author_data[n]['given'] or v
elseif a == 'link' then
author_data[n]['link'] = author_data[n]['link'] or v
end
end
elseif b == 'editor' or b == 'editorlink' then
editor_data[n] = editor_data[n] or {}
if a == 'surname' or a == 'last' then
editor_data[n]['surname'] = editor_data[n]['surname'] or v
elseif a == 'given' or a == 'first' then
editor_data[n]['given'] = editor_data[n]['given'] or v
elseif a == 'link' then
editor_data[n]['link'] = editor_data[n]['link'] or v
end
end
end
end
-- special cases for first author/editor
-- author
author_data[1] = author_data[1] or {}
author_data[1]['surname'] = author_data[1]['surname'] or args.authorsurname or args.authorlast or args.surname or args.last or args.author or args.authors
author_data[1]['given'] = author_data[1]['given'] or args.authorgiven or args.authorfirst or args.given or args.first
author_data[1]['link'] = author_data[1]['link'] or args.authorlink
-- editor
editor_data[1] = editor_data[1] or {}
editor_data[1]['surname'] = editor_data[1]['surname'] or args.editorsurname or args.editorlast or args.editor or args.editors
editor_data[1]['given'] = editor_data[1]['given'] or args.editorgiven or args.editorfirst
editor_data[1]['link'] = editor_data[1]['link'] or args.editorlink
-- add missing tables to sequence
for i = 1, table.maxn(author_data) do
if not author_data[i] then
author_data[i] = {}
end
end
for i = 1, table.maxn(editor_data) do
if not editor_data[i] then
editor_data[i] = {}
end
end
if author_data == {{}} then
author_data = nil
end
if editor_data == {{}} then
editor_data = nil
end
args.author_data = author_data
args.editor_data = editor_data
-- return citation
mw.logObject(args)
if patent then
return citation_patent(args)
else
return citation_core(args)
end
end
function p.citation(frame)
return p._citation(getArgs(frame))
end
return p