Module:Citation/CS1: Difference between revisions
Jump to navigation
Jump to search
D'oh, meant to edit sandbox |
sync to sandbox, mostly translation handles almost uniformity for archiveurl errors. |
||
Line 4: | Line 4: | ||
message_tail = {}; | message_tail = {}; | ||
} | } | ||
local SEEN = {}; | |||
local DATA = {}; | |||
-- Include translation message hooks, ID and error handling configuration settings. | -- Include translation message hooks, ID and error handling configuration settings. | ||
local cfg = | local cfg = require( 'Module:Citation/CS1/Configuration' ); | ||
-- Contains a list of all recognized parameters | -- Contains a list of all recognized parameters | ||
local whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist' ); | local whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist' ); | ||
-- Checks that parameter name is valid | -- Populates numbered arguments in a message string using | ||
-- an argument table. | |||
function substitute( message, arguments ) | |||
if arguments == nil then | |||
return message; | |||
end | |||
message = message .. " "; | |||
for k, v in ipairs( arguments ) do | |||
v = v:gsub( "%%", "%%%%" ); | |||
message = message:gsub( "$" .. k .. "(%D)", v .. "%1" ); | |||
end | |||
message = message:sub(1,-2); | |||
return message; | |||
end | |||
--[[ | |||
Argument wrapper. This function provides support for argument | |||
mapping defined in the configuration file so that multiple names | |||
can be transparently aliased to single internal variable. | |||
]] | |||
function argument_wrapper( args ) | |||
DATA = args; | |||
local tbl = {}; | |||
local mt = { | |||
__index = function ( tbl, k ) | |||
if SEEN[k] then | |||
return nil; | |||
end | |||
local list = cfg.argument_map[k]; | |||
if list == nil then | |||
error( cfg.message_list['unknown_argument_map'] ); | |||
elseif type( list ) == 'string' then | |||
v = DATA[list]; | |||
else | |||
v = selectone( DATA, cfg.argument_map[k], | |||
'redundant_parameters' ); | |||
end | |||
if v == nil then | |||
v = cfg.default_values[k]; | |||
end | |||
SEEN[k] = true; | |||
tbl = rawset( tbl, k, v ); | |||
return v; | |||
end, | |||
} | |||
return setmetatable( tbl, mt ); | |||
end | |||
-- Checks that parameter name is valid using the whitelist | |||
function validate( name ) | function validate( name ) | ||
name = tostring( name ); | name = tostring( name ); | ||
Line 33: | Line 89: | ||
function errorcomment( content, hidden ) | function errorcomment( content, hidden ) | ||
if hidden then | if hidden then | ||
return ' | return substitute( cfg.message_list['hidden-error'], { content } ); | ||
else | else | ||
return ' | return substitute( cfg.message_list['visible-error'], { content } ); | ||
end | end | ||
end | end | ||
Line 43: | Line 99: | ||
of the error message in the output is the responsibility of the calling function. | of the error message in the output is the responsibility of the calling function. | ||
]] | ]] | ||
function seterror( error_id, | function seterror( error_id, arguments, raw, prefix, suffix ) | ||
local error_state = cfg.error_conditions[ error_id ]; | local error_state = cfg.error_conditions[ error_id ]; | ||
prefix = prefix or ""; | prefix = prefix or ""; | ||
Line 57: | Line 113: | ||
local message = error_state.message; | local message = error_state.message; | ||
message = substitute( message, arguments ); | |||
message = wikiescape(message) .. " ([[" .. cfg.message_list['help page link'] .. | message = wikiescape(message) .. " ([[" .. cfg.message_list['help page link'] .. | ||
Line 91: | Line 142: | ||
[']'] = ']', | [']'] = ']', | ||
['{'] = '{', | ['{'] = '{', | ||
['|'] = '|', | ['|'] = '|', | ||
['}'] = '}' } ); | ['}'] = '}' } ); | ||
return text; | return text; | ||
Line 289: | Line 340: | ||
if str:sub(1,1) == "'" then str = "<span />" .. str; end | if str:sub(1,1) == "'" then str = "<span />" .. str; end | ||
if str:sub(-1,-1) == "'" then str = str .. "<span />"; end | if str:sub(-1,-1) == "'" then str = str .. "<span />"; end | ||
-- Remove newlines as they break italics. | |||
return str:gsub( '\n', ' ' ); | return str:gsub( '\n', ' ' ); | ||
end | end | ||
Line 458: | Line 511: | ||
end | end | ||
-- Gets | -- Gets name list from the input arguments | ||
function | function extractnames(args, list_name) | ||
local names = {}; | |||
local | |||
local i = 1; | local i = 1; | ||
local last; | local last; | ||
while true do | while true do | ||
last = selectone( args, cfg.argument_map[list_name .. '-Last'], 'redundant_parameters', i ); | |||
if ( last and "" < last ) then -- just in case someone passed in an empty parameter | if ( last and "" < last ) then -- just in case someone passed in an empty parameter | ||
names[i] = { | |||
last = last, | |||
first = selectone( args, cfg.argument_map[list_name .. '-First'], 'redundant_parameters', i ), | |||
link = selectone( args, cfg.argument_map[list_name .. '-Link'], 'redundant_parameters', i ), | |||
mask = selectone( args, cfg.argument_map[list_name .. '-Mask'], 'redundant_parameters', i ) | |||
} | |||
else | else | ||
break; | break; | ||
Line 550: | Line 531: | ||
i = i + 1; | i = i + 1; | ||
end | end | ||
return | return names; | ||
end | end | ||
Line 617: | Line 598: | ||
-- Chooses one matching parameter from a list of parameters to consider | -- Chooses one matching parameter from a list of parameters to consider | ||
-- Generates an error if more than one match is present. | -- Generates an error if more than one match is present. | ||
function selectone( args, possible, error_condition ) | function selectone( args, possible, error_condition, index ) | ||
local value = nil; | local value = nil; | ||
local selected = ''; | local selected = ''; | ||
local error_list = {}; | local error_list = {}; | ||
if index ~= nil then index = tostring(index); end | |||
-- Handle special case of "#" replaced by empty string | |||
if index == '1' then | |||
for _, v in ipairs( possible ) do | |||
v = v:gsub( "#", "" ); | |||
if args[v] ~= nil then | |||
if value ~= nil and selected ~= v then | |||
table.insert( error_list, v ); | |||
else | |||
value = args[v]; | |||
selected = v; | |||
end | |||
end | |||
end | |||
end | |||
for _, v in ipairs( possible ) do | for _, v in ipairs( possible ) do | ||
if index ~= nil then | |||
v = v:gsub( "#", index ); | |||
end | |||
if args[v] ~= nil then | if args[v] ~= nil then | ||
if value ~= nil then | if value ~= nil then | ||
Line 632: | Line 632: | ||
end | end | ||
end | end | ||
if #error_list > 0 then | if #error_list > 0 then | ||
local error_str = ""; | local error_str = ""; | ||
Line 656: | Line 656: | ||
]] | ]] | ||
function citation0( config, args) | function citation0( config, args) | ||
-- Load Input Parameters | --[[ | ||
Load Input Parameters | |||
The argment_wrapper facillitates the mapping of multiple | |||
aliases to single internal variable. | |||
]] | |||
local A = argument_wrapper( args ); | |||
local i | local i | ||
local PPrefix = | local PPrefix = A['PPrefix'] | ||
local PPPrefix = | local PPPrefix = A['PPPrefix'] | ||
if ( nil ~= | if ( nil ~= A['NoPP'] ) then PPPrefix = "" PPrefix = "" end | ||
-- Pick out the relevant fields from the arguments. Different citation templates | -- Pick out the relevant fields from the arguments. Different citation templates | ||
-- define different field names for the same underlying things. | -- define different field names for the same underlying things. | ||
local Authors = | local Authors = A['Authors']; | ||
local a = | local a = extractnames( args, 'AuthorList' ); | ||
local Coauthors = | local Coauthors = A['Coauthors']; | ||
local Others = | local Others = A['Others']; | ||
local Editors = | local Editors = A['Editors']; | ||
local e = | local e = extractnames( args, 'EditorList' ); | ||
local Year = | local Year = A['Year']; | ||
local PublicationDate = | local PublicationDate = A['PublicationDate']; | ||
local OrigYear = | local OrigYear = A['OrigYear']; | ||
local Date = | local Date = A['Date']; | ||
local LayDate = | local LayDate = A['LayDate']; | ||
------------------------------------------------- Get title data | ------------------------------------------------- Get title data | ||
local Title = | local Title = A['Title']; | ||
local BookTitle = | local BookTitle = A['BookTitle']; | ||
local Conference = | local Conference = A['Conference']; | ||
local TransTitle = | local TransTitle = A['TransTitle']; | ||
local TitleNote = | local TitleNote = A['TitleNote']; | ||
local TitleLink = | local TitleLink = A['TitleLink']; | ||
local Chapter = | local Chapter = A['Chapter']; | ||
local ChapterLink = | local ChapterLink = A['ChapterLink']; | ||
local TransChapter = | local TransChapter = A['TransChapter']; | ||
local TitleType = | local TitleType = A['TitleType']; | ||
local ArchiveURL = | local ArchiveURL = A['ArchiveURL']; | ||
local URL = | local URL = A['URL']; | ||
local ChapterURL = | local ChapterURL = A['ChapterURL']; | ||
local ConferenceURL = | local ConferenceURL = A['ConferenceURL']; | ||
local Periodical = | local Periodical = A['Periodical']; | ||
if ( config.CitationClass == "encyclopaedia" ) then | if ( config.CitationClass == "encyclopaedia" ) then | ||
if ( | if ( Chapter == nil or Chapter == '' ) then | ||
if ( Title | if (Title == nil or Title == "") then | ||
Title = Periodical; | |||
Periodical = nil; | |||
else | |||
Chapter = Title | Chapter = Title | ||
TransChapter = TransTitle | TransChapter = TransTitle | ||
Line 710: | Line 711: | ||
TransTitle = nil | TransTitle = nil | ||
end | end | ||
end | end | ||
end | end | ||
local Series = | |||
local Volume = | local Series = A['Series']; | ||
local Issue = | local Volume = A['Volume']; | ||
local Issue = A['Issue']; | |||
local Position = nil | local Position = nil | ||
local Page, Pages, At, page_type; | local Page, Pages, At, page_type; | ||
Page | Page = A['Page']; | ||
Pages = hyphentodash( A['Pages'] ); | |||
if | At = A['At']; | ||
if Page ~= nil then | |||
if Pages ~= nil or At ~= nil then | |||
elseif | Page = Page .. " " .. seterror('extra_pages'); | ||
At = | Pages = nil; | ||
At = nil; | |||
end | end | ||
elseif Pages ~= nil then | |||
if At ~= nil then | |||
Pages = Pages .. " " .. seterror('extra_pages'); | |||
At = nil; | |||
end | |||
end | |||
local Edition = | local Edition = A['Edition']; | ||
local PublicationPlace = | local PublicationPlace = A['PublicationPlace'] | ||
local Place = | local Place = A['Place']; | ||
if PublicationPlace == nil and Place ~= nil then | if PublicationPlace == nil and Place ~= nil then | ||
PublicationPlace = Place; | PublicationPlace = Place; | ||
Line 739: | Line 744: | ||
if PublicationPlace == Place then Place = nil end | if PublicationPlace == Place then Place = nil end | ||
local PublisherName = | local PublisherName = A['PublisherName']; | ||
local SubscriptionRequired = | local SubscriptionRequired = A['SubscriptionRequired']; | ||
local Via = | local Via = A['Via']; | ||
local AccessDate = | local AccessDate = A['AccessDate']; | ||
local ArchiveDate = | local ArchiveDate = A['ArchiveDate']; | ||
local Agency = | local Agency = A['Agency']; | ||
local DeadURL = | local DeadURL = A['DeadURL'] | ||
local Language = | local Language = A['Language']; | ||
local Format = | local Format = A['Format'] | ||
local Ref = | local Ref = A['Ref'] | ||
local DoiBroken = | local DoiBroken = A['DoiBroken'] | ||
local ID = | local ID = A['ID']; | ||
local ASINTLD = | local ASINTLD = A['ASINTLD']; | ||
local IgnoreISBN = | local IgnoreISBN = A['IgnoreISBN'] | ||
local ID_list = extractids( args ); | local ID_list = extractids( args ); | ||
local Quote = | local Quote = A['Quote']; | ||
local PostScript = | local PostScript = A['PostScript'] | ||
local LaySummary = | local LaySummary = A['LaySummary'] | ||
local LaySource = | local LaySource = A['LaySource']; | ||
local Transcript = | local Transcript = A['Transcript']; | ||
local TranscriptURL = | local TranscriptURL = A['TranscriptURL']; | ||
local sepc = | local sepc = A['Separator'] | ||
local LastAuthorAmp = | local LastAuthorAmp = A['LastAuthorAmp'] | ||
local no_tracking_cats = | local no_tracking_cats = A['NoTracking']; | ||
if ( config.CitationClass == "journal" ) then | if ( config.CitationClass == "journal" ) then | ||
if (URL == nil or URL == "") then | if (URL == nil or URL == "") then | ||
if (ID_list['PMC'] ~= nil) then | if (ID_list['PMC'] ~= nil) then | ||
local Embargo = | local Embargo = A['Embargo']; | ||
if Embargo ~= nil then | if Embargo ~= nil then | ||
local lang = mw.getContentLanguage(); | local lang = mw.getContentLanguage(); | ||
Line 801: | Line 805: | ||
-- Account for the oddity that is {{cite episode}}, before generation of COinS data. | -- Account for the oddity that is {{cite episode}}, before generation of COinS data. | ||
if config.CitationClass == "episode" then | if config.CitationClass == "episode" then | ||
local AirDate = | local AirDate = A['AirDate'] | ||
local SeriesLink = | local SeriesLink = A['SeriesLink'] | ||
local Season = | local Season = A['Season'] | ||
local SeriesNumber = | local SeriesNumber = A['SeriesNumber'] | ||
local Network = | local Network = A['Network'] | ||
local Station = | local Station = A['Station'] | ||
local s = {} | local s = {} | ||
if Issue ~= nil then table.insert(s, cfg.message_list["episode"] .. " " .. Issue) Issue = nil end | if Issue ~= nil then table.insert(s, cfg.message_list["episode"] .. " " .. Issue) Issue = nil end | ||
Line 821: | Line 825: | ||
TitleLink = SeriesLink | TitleLink = SeriesLink | ||
TransTitle = nil | TransTitle = nil | ||
local Sep = | local Sep = (A["SeriesSeparator"] or A["Separator"]) .. " " | ||
Series = table.concat(s, Sep) | Series = table.concat(s, Sep) | ||
ID = table.concat(n, Sep) | ID = table.concat(n, Sep) | ||
Line 880: | Line 884: | ||
end | end | ||
if last ~= nil and first ~= nil then | if last ~= nil and first ~= nil then | ||
table.insert( OCinSauthors, last .. | table.insert( OCinSauthors, last .. ", " .. first ); | ||
elseif last ~= nil then | elseif last ~= nil then | ||
table.insert( OCinSauthors, last ); | table.insert( OCinSauthors, last ); | ||
Line 923: | Line 927: | ||
-- various parts of the citation, but only when they are non-nil. | -- various parts of the citation, but only when they are non-nil. | ||
if ( Authors == nil ) then | if ( Authors == nil ) then | ||
local Maximum = tonumber( | local Maximum = tonumber( A['DisplayAuthors'] ); | ||
-- Preserve old-style implicit et al. | -- Preserve old-style implicit et al. | ||
Line 934: | Line 938: | ||
local control = { | local control = { | ||
sep = | sep = A["AuthorSeparator"] .. " ", | ||
namesep = ( | namesep = (A["AuthorNameSeparator"] or A["NameSeparator"]) .. " ", | ||
format = | format = A["AuthorFormat"], | ||
maximum = Maximum, | maximum = Maximum, | ||
lastauthoramp = LastAuthorAmp | lastauthoramp = LastAuthorAmp | ||
Line 951: | Line 955: | ||
local EditorCount | local EditorCount | ||
if ( Editors == nil ) then | if ( Editors == nil ) then | ||
local Maximum = tonumber( | local Maximum = tonumber( A['DisplayEditors'] ); | ||
-- Preserve old-style implicit et al. | -- Preserve old-style implicit et al. | ||
Line 962: | Line 966: | ||
local control = { | local control = { | ||
sep = | sep = A["EditorSeparator"] .. " ", | ||
namesep = ( | namesep = (A["EditorNameSeparator"] or A["NameSeparator"]) .. " ", | ||
format = | format = A['EditorFormat'], | ||
maximum = Maximum, | maximum = Maximum, | ||
lastauthoramp = LastAuthorAmp | lastauthoramp = LastAuthorAmp | ||
Line 994: | Line 998: | ||
Date = Year | Date = Year | ||
if ( Date ~= nil and Date ~="") then | if ( Date ~= nil and Date ~="") then | ||
local Month = | local Month = A['Month'] | ||
if ( Month ~= nil and Month ~= "") then | if ( Month ~= nil and Month ~= "") then | ||
Date = Month .. " " .. Date | Date = Month .. " " .. Date | ||
local Day = | local Day = A['Day'] | ||
if ( Day ~= nil ) then Date = Day .. " " .. Date end | if ( Day ~= nil ) then Date = Day .. " " .. Date end | ||
else Month = "" | else Month = "" | ||
Line 1,057: | Line 1,061: | ||
end | end | ||
if ( TransTitle and "" < TransTitle ) then TransTitle = " | if ( TransTitle and "" < TransTitle ) then TransTitle = " " .. substitute( cfg.message_list['trans-title'], { TransTitle } ) else TransTitle = "" end | ||
if ( TransChapter and "" < TransChapter ) then TransChapter = " | if ( TransChapter and "" < TransChapter ) then TransChapter = " " .. substitute( cfg.message_list['trans-title'], { TransChapter } ) else TransChapter = "" end | ||
-- Format chapter / article title | -- Format chapter / article title | ||
Line 1,065: | Line 1,069: | ||
if ( Periodical and "" < Periodical ) and (Title ~= nil and Title ~= "" ) | if ( Periodical and "" < Periodical ) and (Title ~= nil and Title ~= "" ) | ||
then | then | ||
Chapter = | Chapter = substitute( cfg.message_list['italic-title'], { (safeforitalics(Chapter)) } ); | ||
else | else | ||
Chapter = | Chapter = substitute( cfg.message_list['quoted-title'], { Chapter } ); | ||
end | end | ||
else | else | ||
Line 1,109: | Line 1,113: | ||
Title = "[[" .. TitleLink .. "|" .. Title .. "]]" end | Title = "[[" .. TitleLink .. "|" .. Title .. "]]" end | ||
if ( Periodical and "" < Periodical ) then | if ( Periodical and "" < Periodical ) then | ||
Title = | Title = substitute( cfg.message_list['quoted-title'], { Title } ); | ||
elseif ( config.CitationClass == "web" | elseif ( config.CitationClass == "web" | ||
or config.CitationClass == "news" | or config.CitationClass == "news" | ||
or config.CitationClass == "pressrelease" ) and | or config.CitationClass == "pressrelease" ) and | ||
Chapter == "" then | Chapter == "" then | ||
Title = | Title = substitute( cfg.message_list['quoted-title'], { Title } ); | ||
else | else | ||
Title = | Title = substitute( cfg.message_list['italic-title'], { (safeforitalics(Title)) } ); | ||
end | end | ||
else | else | ||
Line 1,139: | Line 1,143: | ||
if ( Place ~= nil and Place ~= "" ) then | if ( Place ~= nil and Place ~= "" ) then | ||
if sepc == '.' then | if sepc == '.' then | ||
Place = " " .. cfg.message_list['written'] | Place = " " .. substitute( cfg.message_list['written'], {Place} ) .. sepc .. " "; | ||
else | else | ||
Place = " " .. cfg.message_list['written']:lower() | Place = " " .. substitute( cfg.message_list['written']:lower(), {Place} ) .. sepc .. " "; | ||
end | end | ||
else | else | ||
Line 1,159: | Line 1,163: | ||
if ( nil ~= Position or nil ~= Page or nil ~= Pages ) then At = nil end | if ( nil ~= Position or nil ~= Page or nil ~= Pages ) then At = nil end | ||
if ( nil == Position and "" ~= Position ) then | if ( nil == Position and "" ~= Position ) then | ||
local Minutes = | local Minutes = A['Minutes']; | ||
if ( nil ~= Minutes ) then | if ( nil ~= Minutes ) then | ||
Position = " " .. Minutes .. " " .. cfg.message_list['minutes']; | Position = " " .. Minutes .. " " .. cfg.message_list['minutes']; | ||
else | else | ||
local Time = | local Time = A['Time']; | ||
if ( nil ~= Time ) then | if ( nil ~= Time ) then | ||
local TimeCaption = | local TimeCaption = A['TimeCaption'] | ||
if TimeCaption == nil then | if TimeCaption == nil then | ||
TimeCaption = cfg.message_list['event']; | TimeCaption = cfg.message_list['event']; | ||
Line 1,218: | Line 1,222: | ||
TitleNote = sepc .. " " .. TitleNote else TitleNote = "" end | TitleNote = sepc .. " " .. TitleNote else TitleNote = "" end | ||
if ( Language ~= nil and Language ~="" ) then | if ( Language ~= nil and Language ~="" ) then | ||
Language = " | Language = " " .. substitute( cfg.message_list['language'] , {Language} ) else Language = "" end | ||
if ( Edition ~= nil and Edition ~="" ) then | if ( Edition ~= nil and Edition ~="" ) then | ||
Edition = | Edition = " " .. substitute( cfg.message_list['edition'] , {Edition} ) else Edition = "" end | ||
if ( Volume ~= nil and Volume ~="" ) | if ( Volume ~= nil and Volume ~="" ) | ||
then | then | ||
Line 1,239: | Line 1,243: | ||
if ( Date ~= nil ) then Date = Date else Date = "" end | if ( Date ~= nil ) then Date = Date else Date = "" end | ||
if ( Via ~= nil and Via ~="" ) then | if ( Via ~= nil and Via ~="" ) then | ||
Via = " | Via = " " .. substitute( cfg.message_list['via'], {Via} ) else Via = "" end | ||
if ( AccessDate ~= nil and AccessDate ~="" ) | if ( AccessDate ~= nil and AccessDate ~="" ) | ||
then local retrv_text = " " .. cfg.message_list['retrieved'] | then local retrv_text = " " .. cfg.message_list['retrieved'] | ||
if (sepc ~= ".") then retrv_text = retrv_text:lower() end | if (sepc ~= ".") then retrv_text = retrv_text:lower() end | ||
AccessDate = '<span class="reference-accessdate">' .. sepc | AccessDate = '<span class="reference-accessdate">' .. sepc | ||
.. retrv_text | .. substitute( retrv_text, {AccessDate} ) .. '</span>' | ||
else AccessDate = "" end | else AccessDate = "" end | ||
if ( SubscriptionRequired ~= nil and | if ( SubscriptionRequired ~= nil and | ||
Line 1,273: | Line 1,277: | ||
end | end | ||
Quote = sepc .. | Quote = sepc .." " .. substitute( cfg.message_list['quoted-text'], { Quote } ); | ||
PostScript = "" | PostScript = "" | ||
else | else | ||
Line 1,282: | Line 1,286: | ||
local Archived | local Archived | ||
if ( nil ~= ArchiveURL and "" ~= ArchiveURL ) then | if ( nil ~= ArchiveURL and "" ~= ArchiveURL ) then | ||
if ( ArchiveDate | if ( ArchiveDate == nil or ArchiveDate =="" ) then | ||
ArchiveDate = | ArchiveDate = seterror('archive_missing_date'); | ||
end | end | ||
if ( "no" == DeadURL ) then | if ( "no" == DeadURL ) then | ||
local arch_text = cfg.message_list['archived']; | |||
if (sepc ~= ".") then arch_text = arch_text:lower() end | |||
Archived = sepc .. " " .. substitute( cfg.message_list['archived-not-dead'], | |||
{ externallink( ArchiveURL, arch_text ), ArchiveDate } ); | |||
if OriginalURL == nil or OriginalUrl == '' then | if OriginalURL == nil or OriginalUrl == '' then | ||
Archived = Archived .. " " .. seterror(' | Archived = Archived .. " " .. seterror('archive_missing_url'); | ||
end | end | ||
else | else | ||
if OriginalURL ~= nil and OriginalURL ~= '' then | if OriginalURL ~= nil and OriginalURL ~= '' then | ||
local arch_text = cfg.message_list['archived-dead']; | |||
if (sepc ~= ".") then arch_text = arch_text:lower() end | |||
Archived = sepc .. " " .. substitute( arch_text, | |||
{ externallink( OriginalURL, cfg.message_list['original'] ), ArchiveDate } ); | |||
else | else | ||
local arch_text = cfg.message_list['archived-missing']; | |||
if (sepc ~= ".") then arch_text = arch_text:lower() end | |||
Archived = sepc .. " " .. substitute( arch_text, | |||
{ seterror('archive_missing_url'), ArchiveDate } ); | |||
end | end | ||
end | end | ||
Line 1,355: | Line 1,354: | ||
if ( PublicationDate and PublicationDate ~="" ) then | if ( PublicationDate and PublicationDate ~="" ) then | ||
if Publisher ~= '' then | if Publisher ~= '' then | ||
Publisher = Publisher .. ", " .. cfg.message_list['published'] | Publisher = Publisher .. ", " .. substitute( cfg.message_list['published'], {PublicationDate} ); | ||
else | else | ||
Publisher = PublicationDate; | Publisher = PublicationDate; | ||
Line 1,365: | Line 1,364: | ||
else | else | ||
if ( PublicationDate and PublicationDate ~="" ) then | if ( PublicationDate and PublicationDate ~="" ) then | ||
PublicationDate = " (" .. cfg.message_list['published'] | PublicationDate = " (" .. substitute( cfg.message_list['published'], {PublicationDate} ) .. ")" | ||
else | else | ||
PublicationDate = "" | PublicationDate = "" | ||
Line 1,384: | Line 1,383: | ||
if ( Periodical ~= nil and Periodical ~="" ) then | if ( Periodical ~= nil and Periodical ~="" ) then | ||
if ( Title and Title ~= "" ) or ( TitleNote and TitleNote ~= "" ) then | if ( Title and Title ~= "" ) or ( TitleNote and TitleNote ~= "" ) then | ||
Periodical = sepc .. " | Periodical = sepc .. " " .. substitute( cfg.message_list['italic-title'], { (safeforitalics(Periodical)) } ) | ||
else | else | ||
Periodical = | Periodical = substitute( cfg.message_list['italic-title'], { (safeforitalics(Periodical)) } ) | ||
end | end | ||
else Periodical = "" end | else Periodical = "" end | ||
Line 1,417: | Line 1,416: | ||
if ( "" ~= Authors ) then | if ( "" ~= Authors ) then | ||
if (Coauthors ~= "") | if (Coauthors ~= "") | ||
then Authors = Authors .. " | then Authors = Authors .. A['AuthorSeparator'] .. " " .. Coauthors | ||
end | end | ||
if ( "" ~= Date ) | if ( "" ~= Date ) | ||
Line 1,531: | Line 1,530: | ||
if #z.message_tail ~= 0 then | if #z.message_tail ~= 0 then | ||
text = text .. " "; | |||
for i,v in ipairs( z.message_tail ) do | for i,v in ipairs( z.message_tail ) do | ||
if v[1] ~= nil and v[1] ~= "" then | if v[1] ~= nil and v[1] ~= "" then | ||
Line 1,542: | Line 1,542: | ||
end | end | ||
if no_tracking_cats == | if no_tracking_cats == nil then | ||
for _, v in ipairs( z.error_categories ) do | for _, v in ipairs( z.error_categories ) do | ||
text = text .. '[[Category:' .. v ..']]'; | text = text .. '[[Category:' .. v ..']]'; | ||
Line 1,601: | Line 1,601: | ||
return z | return z | ||
Revision as of 00:53, 17 April 2013
<section begin=header />
Warning | This Lua module is used on 3,000,000+ pages. To avoid large-scale disruption and unnecessary server load, any changes to this module should first be tested in its /sandbox or /testcases subpages. The tested changes can then be added to this page in a single edit. Please consider discussing any changes on the talk page before implementing them. |
This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
<section end=header />
This module and associated sub-modules support the Citation Style 1 and Citation Style 2 citation templates. In general, it is not intended to be called directly, but is called by one of the core CS1 and CS2 templates. <section begin=module_components_table /> These files comprise the module support for cs1|2 citation templates:
<section end=module_components_table />
Other documentation:
local z = {
error_categories = {};
error_ids = {};
message_tail = {};
}
local SEEN = {};
local DATA = {};
-- Include translation message hooks, ID and error handling configuration settings.
local cfg = require( 'Module:Citation/CS1/Configuration' );
-- Contains a list of all recognized parameters
local whitelist = mw.loadData( 'Module:Citation/CS1/Whitelist' );
-- Populates numbered arguments in a message string using
-- an argument table.
function substitute( message, arguments )
if arguments == nil then
return message;
end
message = message .. " ";
for k, v in ipairs( arguments ) do
v = v:gsub( "%%", "%%%%" );
message = message:gsub( "$" .. k .. "(%D)", v .. "%1" );
end
message = message:sub(1,-2);
return message;
end
--[[
Argument wrapper. This function provides support for argument
mapping defined in the configuration file so that multiple names
can be transparently aliased to single internal variable.
]]
function argument_wrapper( args )
DATA = args;
local tbl = {};
local mt = {
__index = function ( tbl, k )
if SEEN[k] then
return nil;
end
local list = cfg.argument_map[k];
if list == nil then
error( cfg.message_list['unknown_argument_map'] );
elseif type( list ) == 'string' then
v = DATA[list];
else
v = selectone( DATA, cfg.argument_map[k],
'redundant_parameters' );
end
if v == nil then
v = cfg.default_values[k];
end
SEEN[k] = true;
tbl = rawset( tbl, k, v );
return v;
end,
}
return setmetatable( tbl, mt );
end
-- Checks that parameter name is valid using the whitelist
function validate( name )
name = tostring( name );
-- Normal arguments
if whitelist.basic_arguments[ name ] then
return true;
end
-- Arguments with numbers in them
name = name:gsub( "%d+", "#" );
if whitelist.numbered_arguments[ name ] then
return true;
end
-- Not found, argument not supported.
return false
end
-- Formats a comment for error trapping
function errorcomment( content, hidden )
if hidden then
return substitute( cfg.message_list['hidden-error'], { content } );
else
return substitute( cfg.message_list['visible-error'], { content } );
end
end
--[[
Sets an error condition and returns the appropriate error message. The actual placement
of the error message in the output is the responsibility of the calling function.
]]
function seterror( error_id, arguments, raw, prefix, suffix )
local error_state = cfg.error_conditions[ error_id ];
prefix = prefix or "";
suffix = suffix or "";
if error_state == nil then
error( cfg.message_list['undefined_error'] );
end
if error_state.category ~= nil and error_state.category ~= "" then
table.insert( z.error_categories, error_state.category );
end
local message = error_state.message;
message = substitute( message, arguments );
message = wikiescape(message) .. " ([[" .. cfg.message_list['help page link'] ..
"#" .. error_state.anchor .. "|" ..
cfg.message_list['help page label'] .. "]])";
z.error_ids[ error_id ] = true;
if (error_id == 'bare_url_missing_title' or error_id == 'trans_missing_title')
and z.error_ids['citation_missing_title'] then
return '', false;
end
message = prefix .. message .. suffix;
if raw == true then
return message, error_state.hidden;
end
return errorcomment( message, error_state.hidden );
end
-- This returns a string with HTML character entities for wikitext markup characters.
function wikiescape(text)
text = text:gsub( '[&\'%[%]{|}]', {
['&'] = '&',
["'"] = ''',
['['] = '[',
[']'] = ']',
['{'] = '{',
['|'] = '|',
['}'] = '}' } );
return text;
end
-- Formats a wiki style external link
function externallinkid(options)
local sep = options.separator or " "
options.suffix = options.suffix or ""
local url_string = options.id
if options.encode == true or options.encode == nil then
url_string = mw.uri.encode( url_string );
end
return "[[" .. options.link .. "|" .. options.label .. "]]" .. sep .. "[" ..
options.prefix .. url_string .. options.suffix .. " " .. mw.text.nowiki(options.id) .. "]"
end
-- Formats a wiki style internal link
function internallinkid(options)
local sep = options.separator or " "
options.suffix = options.suffix or ""
return "[[" .. options.link .. "|" .. options.label .. "]]" .. sep .. "[[" ..
options.prefix .. options.id .. options.suffix .. "|" .. mw.text.nowiki(options.id) .. "]]"
end
-- Format an external link with error checking
function externallink( URL, label )
local error_str = "";
if label == nil or label == "" then
label = URL;
error_str = seterror( 'bare_url_missing_title', {}, false, " " );
end
if not checkurl( URL ) then
error_str = seterror( 'bad_url', {}, false, " " ) .. error_str;
end
return "[" .. URL .. ' ' .. safeforurl( label ) .. "]" .. error_str;
end
-- Formats a link to Amazon
function amazon(id, domain)
if ( nil == domain ) then
domain = "com"
elseif ( "jp" == domain or "uk" == domain ) then
domain = "co." .. domain
end
local handler = cfg.id_handlers['ASIN'];
return externallinkid({link = handler.link,
label=handler.label , prefix="//www.amazon."..domain.."/dp/",id=id,
encode=handler.encode, separator = handler.separator})
end
-- Formats a DOI and checks for DOI errors.
function doi(id, inactive)
local cat = ""
local handler = cfg.id_handlers['DOI'];
local text;
if ( inactive ~= nil ) then
text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
table.insert( z.error_categories, "Pages with DOIs inactive since " .. selectyear(inactive) );
inactive = " (" .. cfg.message_list['inactive'] .. " " .. inactive .. ")"
else
text = externallinkid({link = handler.link, label = handler.label,
prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
inactive = ""
end
if ( string.sub(id,1,3) ~= "10." ) then
cat = seterror( 'bad_doi' );
end
return text .. inactive .. cat
end
-- Formats an OpenLibrary link, and checks for associated errors.
function openlibrary(id)
local code = id:sub(-1,-1)
local handler = cfg.id_handlers['OL'];
if ( code == "A" ) then
return externallinkid({link=handler.link, label=handler.label,
prefix="http://openlibrary.org/authors/OL",id=id, separator=handler.separator,
encode = handler.encode})
elseif ( code == "M" ) then
return externallinkid({link=handler.link, label=handler.label,
prefix="http://openlibrary.org/books/OL",id=id, separator=handler.separator,
encode = handler.encode})
elseif ( code == "W" ) then
return externallinkid({link=handler.link, label=handler.label,
prefix= "http://openlibrary.org/works/OL",id=id, separator=handler.separator,
encode = handler.encode})
else
return externallinkid({link=handler.link, label=handler.label,
prefix= "http://openlibrary.org/OL",id=id, separator=handler.separator,
encode = handler.encode}) ..
' ' .. seterror( 'bad_ol' );
end
end
--[[
Determines whether an URL string is valid
At present the only check is whether the string appears to
be prefixed with a URI scheme. It is not determined whether
the URI scheme is valid or whether the URL is otherwise well
formed.
]]
function checkurl( url_str )
if url_str:sub(1,2) == "//" then
-- Protocol-less URLs
return true;
elseif url_str:match( "^[^/]*:" ) ~= nil then
-- Look for ":" prefix and assume it is a URI scheme
return true;
else
-- Anything else is an error
return false;
end
end
-- Removes irrelevant text and dashes from ISBN number
-- Similar to that used for Special:BookSources
function cleanisbn( isbn_str )
return isbn_str:gsub( "[^-0-9X]", "" );
end
-- Determines whether an ISBN string is valid
function checkisbn( isbn_str )
isbn_str = cleanisbn( isbn_str ):gsub( "-", "" );
local len = isbn_str:len();
if len ~= 10 and len ~= 13 then
return false;
end
local temp = 0;
if len == 10 then
if isbn_str:match( "^%d*X?$" ) == nil then return false; end
isbn_str = { isbn_str:byte(1, len) };
for i, v in ipairs( isbn_str ) do
if v == string.byte( "X" ) then
temp = temp + 10*( 11 - i );
else
temp = temp + tonumber( string.char(v) )*(11-i);
end
end
return temp % 11 == 0;
else
if isbn_str:match( "^%d*$" ) == nil then return false; end
isbn_str = { isbn_str:byte(1, len) };
for i, v in ipairs( isbn_str ) do
temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );
end
return temp % 10 == 0;
end
end
-- Gets the display text for a wikilink like [[A|B]] or [[B]] gives B
function removewikilink( str )
str = str:gsub( "%[%[[^|%]]*|([^%]]*)%]%]", "%1" );
str = str:gsub( "%[%[([^%]]*)%]%]", "%1" );
return str
end
-- Escape sequences for content that will be used for URL descriptions
function safeforurl( str )
if str:match( "%[%[.-%]%]" ) ~= nil then
table.insert( z.message_tail, { seterror( 'wikilink_in_url', {}, true ) } );
end
return str:gsub( '[%[%]\n]', {
['['] = '[',
[']'] = ']',
['\n'] = ' ' } );
end
-- Converts a hyphen to a dash
function hyphentodash( str )
if str == nil then
return nil;
end
if str:match( "[%[%]{}<>]" ) ~= nil then
return str;
end
return str:gsub( '-', '–' );
end
-- Protects a string that will be wrapped in wiki italic markup '' ... ''
function safeforitalics( str )
--[[ Note: We can not use <i> for italics, as the expected behavior for
italics specified by ''...'' in the title is that they will be inverted
(i.e. unitalicized) in the resulting references. In addition, <i> and ''
tend to interact poorly under Mediawiki's HTML tidy. ]]
if str == nil or str == '' then
return str;
else
if str:sub(1,1) == "'" then str = "<span />" .. str; end
if str:sub(-1,-1) == "'" then str = str .. "<span />"; end
-- Remove newlines as they break italics.
return str:gsub( '\n', ' ' );
end
end
--[[
Joins a sequence of strings together while checking for duplicate separation
characters.
]]
function safejoin( tbl, duplicate_char )
--[[
Note: we use string functions here, rather than ustring functions.
This has considerably faster performance and should work correctly as
long as the duplicate_char is strict ASCII. The strings
in tbl may be ASCII or UTF8.
]]
local str = '';
local comp = '';
local end_chr = '';
local trim;
for _, value in ipairs( tbl ) do
if value == nil then value = ''; end
if str == '' then
str = value;
elseif value ~= '' then
if value:sub(1,1) == '<' then
-- Special case of values enclosed in spans and other markup.
comp = value:gsub( "%b<>", "" );
else
comp = value;
end
if comp:sub(1,1) == duplicate_char then
trim = false;
end_chr = str:sub(-1,-1);
-- str = str .. "<HERE(enchr=" .. end_chr.. ")"
if end_chr == duplicate_char then
str = str:sub(1,-2);
elseif end_chr == "'" then
if str:sub(-3,-1) == duplicate_char .. "''" then
str = str:sub(1, -4) .. "''";
elseif str:sub(-5,-1) == duplicate_char .. "]]''" then
trim = true;
elseif str:sub(-4,-1) == duplicate_char .. "]''" then
trim = true;
end
elseif end_chr == "]" then
if str:sub(-3,-1) == duplicate_char .. "]]" then
trim = true;
elseif str:sub(-2,-1) == duplicate_char .. "]" then
trim = true;
end
elseif end_chr == " " then
if str:sub(-2,-1) == duplicate_char .. " " then
str = str:sub(1,-3);
end
end
if trim then
if value ~= comp then
local dup2 = duplicate_char;
if dup2:match( "%A" ) then dup2 = "%" .. dup2; end
value = value:gsub( "(%b<>)" .. dup2, "%1", 1 )
else
value = value:sub( 2, -1 );
end
end
end
str = str .. value;
end
end
return str;
end
--[[
Return the year portion of a date string, if possible.
Returns empty string if the argument can not be interpreted
as a year.
]]
function selectyear( str )
-- Is the input a simple number?
local num = tonumber( str );
if num ~= nil and num > 0 and num < 2100 and num == math.abs(num) then
return str;
else
-- Use formatDate to interpret more complicated formats
local lang = mw.getContentLanguage();
local good, result;
good, result = pcall( lang.formatDate, lang, 'Y', str )
if good then
return result;
else
-- Can't make sense of this input, return blank.
return "";
end
end
end
-- Attempts to convert names to initials.
function reducetoinitials(first)
local initials = {}
for word in string.gmatch(first, "%S+") do
table.insert(initials, string.sub(word,1,1)) -- Vancouver format does not include full stops.
end
return table.concat(initials) -- Vancouver format does not include spaces.
end
-- Formats a list of people (e.g. authors / editors)
function listpeople(control, people)
local sep = control.sep;
if sep:sub(-1,-1) ~= " " then sep = sep .. " " end
local namesep = control.namesep
local format = control.format
local maximum = control.maximum
local lastauthoramp = control.lastauthoramp;
local text = {}
local etal = false;
for i,person in ipairs(people) do
if (person.last ~= nil or person.last ~= "") then
local mask = person.mask
local one
if ( maximum ~= nil and i == maximum + 1 ) then
etal = true;
break;
elseif (mask ~= nil) then
local n = tonumber(mask)
if (n ~= nil) then
one = string.rep("—",n)
else
one = mask
end
else
one = person.last
local first = person.first
if (first ~= nil and first ~= '') then
if ( "vanc" == format ) then first = reducetoinitials(first) end
one = one .. namesep .. first
end
if (person.link ~= nil and person.link ~= "") then one = "[[" .. person.link .. "|" .. one .. "]]" end
end
table.insert(text, one)
end
end
local count = #text;
if count > 1 and lastauthoramp ~= nil and lastauthoramp ~= "" and not etal then
text[count-1] = text[count-1] .. " & " .. text[count];
text[count] = nil;
end
local result = table.concat(text, sep) -- construct list
if etal then
local etal_text = cfg.message_list['et al'];
result = result .. " " .. etal_text;
end
-- if necessary wrap result in <span> tag to format in Small Caps
if ( "scap" == format ) then result =
'<span class="smallcaps" style="font-variant:small-caps">' .. result .. '</span>';
end
return result, count
end
-- Generates a CITEREF anchor ID.
function anchorid( options )
return "CITEREF" .. mw.uri.anchorEncode( table.concat( options ) );
end
-- Gets name list from the input arguments
function extractnames(args, list_name)
local names = {};
local i = 1;
local last;
while true do
last = selectone( args, cfg.argument_map[list_name .. '-Last'], 'redundant_parameters', i );
if ( last and "" < last ) then -- just in case someone passed in an empty parameter
names[i] = {
last = last,
first = selectone( args, cfg.argument_map[list_name .. '-First'], 'redundant_parameters', i ),
link = selectone( args, cfg.argument_map[list_name .. '-Link'], 'redundant_parameters', i ),
mask = selectone( args, cfg.argument_map[list_name .. '-Mask'], 'redundant_parameters', i )
}
else
break;
end
i = i + 1;
end
return names;
end
-- Populates ID table from arguments using configuration settings
function extractids( args )
local id_list = {};
for k, v in pairs( cfg.id_handlers ) do
id_list[k] = selectone( args, v.parameters, 'redundant_parameters' );
end
return id_list;
end
-- Takes a table of IDs and turns it into a table of formatted ID outputs.
function buildidlist( id_list, options )
local handler;
local new_list = {};
for k, v in pairs( id_list ) do
handler = {};
--Becasue cfg is read-only we have to copy it the hard way.
for k2, v2 in pairs( cfg.id_handlers[k] ) do
handler[k2] = v2;
end
handler['id'] = v;
if handler.mode == 'external' then
table.insert( new_list, {handler.label, externallinkid( handler ) } );
elseif handler.mode == 'internal' then
table.insert( new_list, {handler.label, internallinkid( handler ) } );
elseif handler.mode == 'manual' then
if k == 'DOI' then
table.insert( new_list, {handler.label, doi( v, options.DoiBroken ) } );
elseif k == 'ASIN' then
table.insert( new_list, {handler.label, amazon( v, options.ASINTLD ) } );
elseif k == 'OL' then
table.insert( new_list, {handler.label, openlibrary( v ) } );
elseif k == 'ISBN' then
local ISBN = internallinkid( handler );
if not checkisbn( v ) and ( options.IgnoreISBN == nil or options.IgnoreISBN == "" ) then
ISBN = ISBN .. seterror( 'bad_isbn', {}, false, " ", "" );
end
table.insert( new_list, {handler.label, ISBN } );
else
error( cfg.message_list['unknown_manual_ID'] );
end
else
error( cfg.message_list['unknown_ID_mode'] );
end
end
function comp( a, b )
return a[1] < b[1];
end
table.sort( new_list, comp );
for k, v in ipairs( new_list ) do
new_list[k] = v[2];
end
return new_list;
end
-- Chooses one matching parameter from a list of parameters to consider
-- Generates an error if more than one match is present.
function selectone( args, possible, error_condition, index )
local value = nil;
local selected = '';
local error_list = {};
if index ~= nil then index = tostring(index); end
-- Handle special case of "#" replaced by empty string
if index == '1' then
for _, v in ipairs( possible ) do
v = v:gsub( "#", "" );
if args[v] ~= nil then
if value ~= nil and selected ~= v then
table.insert( error_list, v );
else
value = args[v];
selected = v;
end
end
end
end
for _, v in ipairs( possible ) do
if index ~= nil then
v = v:gsub( "#", index );
end
if args[v] ~= nil then
if value ~= nil then
table.insert( error_list, v );
else
value = args[v];
selected = v;
end
end
end
if #error_list > 0 then
local error_str = "";
for _, k in ipairs( error_list ) do
if error_str ~= "" then error_str = error_str .. ", " end
error_str = error_str .. "<code>|" .. k .. "=</code>";
end
if #error_list > 1 then
error_str = error_str .. ", and ";
else
error_str = error_str .. " and ";
end
error_str = error_str .. "<code>|" .. selected .. "=</code>";
table.insert( z.message_tail, { seterror( error_condition, {error_str}, true ) } );
end
return value, selected;
end
--[[
This is the main function foing the majority of the citation
formatting.
]]
function citation0( config, args)
--[[
Load Input Parameters
The argment_wrapper facillitates the mapping of multiple
aliases to single internal variable.
]]
local A = argument_wrapper( args );
local i
local PPrefix = A['PPrefix']
local PPPrefix = A['PPPrefix']
if ( nil ~= A['NoPP'] ) then PPPrefix = "" PPrefix = "" end
-- Pick out the relevant fields from the arguments. Different citation templates
-- define different field names for the same underlying things.
local Authors = A['Authors'];
local a = extractnames( args, 'AuthorList' );
local Coauthors = A['Coauthors'];
local Others = A['Others'];
local Editors = A['Editors'];
local e = extractnames( args, 'EditorList' );
local Year = A['Year'];
local PublicationDate = A['PublicationDate'];
local OrigYear = A['OrigYear'];
local Date = A['Date'];
local LayDate = A['LayDate'];
------------------------------------------------- Get title data
local Title = A['Title'];
local BookTitle = A['BookTitle'];
local Conference = A['Conference'];
local TransTitle = A['TransTitle'];
local TitleNote = A['TitleNote'];
local TitleLink = A['TitleLink'];
local Chapter = A['Chapter'];
local ChapterLink = A['ChapterLink'];
local TransChapter = A['TransChapter'];
local TitleType = A['TitleType'];
local ArchiveURL = A['ArchiveURL'];
local URL = A['URL'];
local ChapterURL = A['ChapterURL'];
local ConferenceURL = A['ConferenceURL'];
local Periodical = A['Periodical'];
if ( config.CitationClass == "encyclopaedia" ) then
if ( Chapter == nil or Chapter == '' ) then
if (Title == nil or Title == "") then
Title = Periodical;
Periodical = nil;
else
Chapter = Title
TransChapter = TransTitle
Title = nil
TransTitle = nil
end
end
end
local Series = A['Series'];
local Volume = A['Volume'];
local Issue = A['Issue'];
local Position = nil
local Page, Pages, At, page_type;
Page = A['Page'];
Pages = hyphentodash( A['Pages'] );
At = A['At'];
if Page ~= nil then
if Pages ~= nil or At ~= nil then
Page = Page .. " " .. seterror('extra_pages');
Pages = nil;
At = nil;
end
elseif Pages ~= nil then
if At ~= nil then
Pages = Pages .. " " .. seterror('extra_pages');
At = nil;
end
end
local Edition = A['Edition'];
local PublicationPlace = A['PublicationPlace']
local Place = A['Place'];
if PublicationPlace == nil and Place ~= nil then
PublicationPlace = Place;
end
if PublicationPlace == Place then Place = nil end
local PublisherName = A['PublisherName'];
local SubscriptionRequired = A['SubscriptionRequired'];
local Via = A['Via'];
local AccessDate = A['AccessDate'];
local ArchiveDate = A['ArchiveDate'];
local Agency = A['Agency'];
local DeadURL = A['DeadURL']
local Language = A['Language'];
local Format = A['Format']
local Ref = A['Ref']
local DoiBroken = A['DoiBroken']
local ID = A['ID'];
local ASINTLD = A['ASINTLD'];
local IgnoreISBN = A['IgnoreISBN']
local ID_list = extractids( args );
local Quote = A['Quote'];
local PostScript = A['PostScript']
local LaySummary = A['LaySummary']
local LaySource = A['LaySource'];
local Transcript = A['Transcript'];
local TranscriptURL = A['TranscriptURL'];
local sepc = A['Separator']
local LastAuthorAmp = A['LastAuthorAmp']
local no_tracking_cats = A['NoTracking'];
if ( config.CitationClass == "journal" ) then
if (URL == nil or URL == "") then
if (ID_list['PMC'] ~= nil) then
local Embargo = A['Embargo'];
if Embargo ~= nil then
local lang = mw.getContentLanguage();
local good1, result1, good2, result2;
good1, result1 = pcall( lang.formatDate, lang, 'U', Embargo );
good2, result2 = pcall( lang.formatDate, lang, 'U' );
if good1 and good2 and tonumber( result1 ) < tonumber( result2 ) then
URL = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC'];
end
else
URL = "http://www.ncbi.nlm.nih.gov/pmc/articles/PMC" .. ID_list['PMC'];
end
end
end
end
-- At this point fields may be nil if they weren't specified in the template use. We can use that fact.
-- Account for the oddity that is {{cite conference}}, before generation of COinS data.
if ( BookTitle ) then
Chapter = Title
ChapterLink = TitleLink
TransChapter = TransTitle
Title = BookTitle
TitleLink = nil
TransTitle = nil
end
-- Account for the oddity that is {{cite episode}}, before generation of COinS data.
if config.CitationClass == "episode" then
local AirDate = A['AirDate']
local SeriesLink = A['SeriesLink']
local Season = A['Season']
local SeriesNumber = A['SeriesNumber']
local Network = A['Network']
local Station = A['Station']
local s = {}
if Issue ~= nil then table.insert(s, cfg.message_list["episode"] .. " " .. Issue) Issue = nil end
if Season ~= nil then table.insert(s, cfg.message_list["season"] .. " " .. Season) end
if SeriesNumber ~= nil then table.insert(s, cfg.message_list["series"] .. " " .. SeriesNumber) end
local n = {}
if Network ~= nil then table.insert(n, Network) end
if Station ~= nil then table.insert(n, Station) end
Date = Date or AirDate
Chapter = Title
ChapterLink = TitleLink
TransChapter = TransTitle
Title = Series
TitleLink = SeriesLink
TransTitle = nil
local Sep = (A["SeriesSeparator"] or A["Separator"]) .. " "
Series = table.concat(s, Sep)
ID = table.concat(n, Sep)
end
-- These data form a COinS tag (see <http://ocoins.info/>) which allows
-- automated tools to parse the citation information.
local OCinSdata = {} -- COinS metadata excluding id, bibcode, doi, etc.
local ctx_ver = "Z39.88-2004"
OCinSdata.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"
if ( nil ~= Periodical ) then
OCinSdata.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal"
OCinSdata["rft.genre"] = "article"
OCinSdata["rft.jtitle"] = Periodical
if ( nil ~= Title ) then OCinSdata["rft.atitle"] = Title end
end
if ( nil ~= Chapter and "" ~= Chapter) then
OCinSdata.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"
OCinSdata["rft.genre"] = "bookitem"
OCinSdata["rft.btitle"] = Chapter
if ( nil ~= Title ) then OCinSdata["rft.atitle"] = Title end
else
OCinSdata["rft.genre"] = "book"
if ( nil ~= Title ) then OCinSdata["rft.btitle"] = Title end
end
OCinSdata["rft.place"] = PublicationPlace
OCinSdata["rft.date"] = Date or Year or PublicationDate
OCinSdata["rft.series"] = Series
OCinSdata["rft.volume"] = Volume
OCinSdata["rft.issue"] = Issue
OCinSdata["rft.pages"] = Page or Pages or At
OCinSdata["rft.edition"] = Edition
OCinSdata["rft.pub"] = PublisherName
for k, v in pairs( ID_list ) do
if k == 'ISBN' then
v = cleanisbn( v );
end
if string.sub( cfg.id_handlers[k].COinS or "info", 1, 4 ) ~= 'info' then
OCinSdata[ cfg.id_handlers[k].COinS ] = v;
end
end
OCinSdata.rft_id = URL or ChapterURL
local last, first;
local OCinSauthors = {};
for k, v in ipairs( a ) do
last = v.last;
first = v.first;
if k == 1 then
if last ~= nil then
OCinSdata["rft.aulast"] = last;
end
if first ~= nil then
OCinSdata["rft.aufirst"] = first;
end
end
if last ~= nil and first ~= nil then
table.insert( OCinSauthors, last .. ", " .. first );
elseif last ~= nil then
table.insert( OCinSauthors, last );
end
end
local OCinSids = {} -- COinS data only for id, bibcode, doi, pmid, etc.
for k, v in pairs( ID_list ) do
if string.sub( cfg.id_handlers[k].COinS or "", 1, 4 ) == 'info' then
OCinSids[ cfg.id_handlers[k].COinS ] = v;
end
end
local OCinStitle = "ctx_ver=" .. ctx_ver -- such as "Z39.88-2004"
for name,value in pairs(OCinSdata) do
OCinStitle = OCinStitle .. "&" .. name .. "=" .. mw.uri.encode( removewikilink(value) );
end
for _, value in ipairs(OCinSauthors) do
OCinStitle = OCinStitle .. "&rft.au=" .. mw.uri.encode( removewikilink(value) );
end
for name,value in pairs(OCinSids) do
OCinStitle = OCinStitle .. "&rft_id=" .. mw.uri.encode(name .. "/" .. removewikilink(value) );
end
local this_page = mw.title.getCurrentTitle();
OCinStitle = OCinStitle .. "&rfr_id=info:sid/" .. mw.site.server:match( "[^/]*$" ) .. ":"
.. this_page.prefixedText -- end COinS data by page's non-encoded pagename
if (Periodical ~= nil and Periodical ~= "") and
(Chapter == nil or Chapter == '') and
(Title ~= nil and Title ~= "") then
Chapter = Title
ChapterLink = TitleLink
TransChapter = TransTitle
Title = nil
TitleLink = nil
TransTitle = nil
end
-- Now perform various field substitutions.
-- We also add leading spaces and surrounding markup and punctuation to the
-- various parts of the citation, but only when they are non-nil.
if ( Authors == nil ) then
local Maximum = tonumber( A['DisplayAuthors'] );
-- Preserve old-style implicit et al.
if Maximum == nil and #a == 9 then
Maximum = 8;
table.insert( z.message_tail, { seterror('implict_etal_author', {}, true ) } );
elseif Maximum == nil then
Maximum = #a + 1;
end
local control = {
sep = A["AuthorSeparator"] .. " ",
namesep = (A["AuthorNameSeparator"] or A["NameSeparator"]) .. " ",
format = A["AuthorFormat"],
maximum = Maximum,
lastauthoramp = LastAuthorAmp
}
-- If the coauthor field is also used, prevent ampersand and et al. formatting.
if Coauthors ~= nil and Coauthors ~= "" then
control.lastauthoramp = nil;
control.maximum = #a + 1;
end
Authors = listpeople(control, a)
end
local EditorCount
if ( Editors == nil ) then
local Maximum = tonumber( A['DisplayEditors'] );
-- Preserve old-style implicit et al.
if Maximum == nil and #e == 4 then
Maximum = 3;
table.insert( z.message_tail, { seterror('implict_etal_editor', {}, true) } );
elseif Maximum == nil then
Maximum = #e + 1;
end
local control = {
sep = A["EditorSeparator"] .. " ",
namesep = (A["EditorNameSeparator"] or A["NameSeparator"]) .. " ",
format = A['EditorFormat'],
maximum = Maximum,
lastauthoramp = LastAuthorAmp
}
Editors, EditorCount = listpeople(control, e)
else
EditorCount = 1;
end
if ( Date == nil or Date == "") then
-- there's something hinky with how this adds dashes to perfectly-good free-standing years
--[[ Date = Year
if ( Date ~= nil ) then
local Month = args.month
if ( Month == nil ) then
local Began = args.began
local Ended = args.ended
if Began ~= nil and Ended ~= nil then
Month = Began .. "–" .. Ended
else
Month = "–"
end
end
Date = Month .. " " .. Date
local Day = args.day
if ( Day ~= nil ) then Date = Day .. " " .. Date end
end
]] -- so let's use the original version for now
Date = Year
if ( Date ~= nil and Date ~="") then
local Month = A['Month']
if ( Month ~= nil and Month ~= "") then
Date = Month .. " " .. Date
local Day = A['Day']
if ( Day ~= nil ) then Date = Day .. " " .. Date end
else Month = ""
end
else Date = ""
end
end
if ( PublicationDate == Date or PublicationDate == Year ) then PublicationDate = nil end
if( (Date == nil or Date == "") and PublicationDate ~= nil ) then
Date = PublicationDate;
PublicationDate = nil;
end
-- Captures the value for Date prior to adding parens or other textual transformations
local DateIn = Date
if ( URL == nil or URL == '' ) and
( ChapterURL == nil or ChapterURL == '' ) and
( ArchiveURL == nil or ArchiveURL == '' ) and
( ConferenceURL == nil or ConferenceURL == '' ) and
( TranscriptURL == nil or TranscriptURL == '' ) then
-- Test if cite web is called without giving a URL
if ( config.CitationClass == "web" ) then
table.insert( z.message_tail, { seterror( 'cite_web_url', {}, true ) } );
end
-- Test if accessdate is given without giving a URL
if ( AccessDate ~= nil and AccessDate ~= '' ) then
table.insert( z.message_tail, { seterror( 'accessdate_missing_url', {}, true ) } );
AccessDate = nil;
end
-- Test if format is given without giving a URL
if ( Format ~= nil and Format ~= '' ) then
Format = Format .. seterror( 'format_missing_url' );
end
end
-- Test if citation has no title
if ( Chapter == nil or Chapter == "" ) and
( Title == nil or Title == "" ) and
( Periodical == nil or Periodical == "" ) and
( Conference == nil or Conference == "" ) and
( TransTitle == nil or TransTitle == "" ) and
( TransChapter == nil or TransChapter == "" ) then
table.insert( z.message_tail, { seterror( 'citation_missing_title', {}, true ) } );
end
if ( Format ~= nil and Format ~="" ) then
Format = " (" .. Format .. ")" else Format = "" end
local OriginalURL = URL
DeadURL = DeadURL:lower();
if ( ArchiveURL and "" < ArchiveURL ) then
if ( DeadURL ~= "no" ) then
URL = ArchiveURL
end
end
if ( TransTitle and "" < TransTitle ) then TransTitle = " " .. substitute( cfg.message_list['trans-title'], { TransTitle } ) else TransTitle = "" end
if ( TransChapter and "" < TransChapter ) then TransChapter = " " .. substitute( cfg.message_list['trans-title'], { TransChapter } ) else TransChapter = "" end
-- Format chapter / article title
if ( Chapter ~= nil and Chapter ~= "" ) then
if ( ChapterLink and "" < ChapterLink ) then Chapter = "[[" .. ChapterLink .. "|" .. Chapter .. "]]" end
if ( Periodical and "" < Periodical ) and (Title ~= nil and Title ~= "" )
then
Chapter = substitute( cfg.message_list['italic-title'], { (safeforitalics(Chapter)) } );
else
Chapter = substitute( cfg.message_list['quoted-title'], { Chapter } );
end
else
Chapter = "";
end
local TransError = ""
if TransChapter ~= "" and Chapter == "" then
TransError = " " .. seterror( 'trans_missing_chapter' );
end
Chapter = Chapter .. TransChapter
if Chapter ~= "" then
if ( ChapterLink == nil ) then
if ( ChapterURL and "" < ChapterURL ) then
Chapter = externallink( ChapterURL, Chapter ) .. TransError;
if URL == nil or URL == "" then
Chapter = Chapter .. Format;
Format = "";
end
elseif ( URL and "" < URL ) then
Chapter = externallink( URL, Chapter ) .. TransError .. Format;
URL = nil
Format = ""
else
Chapter = Chapter .. TransError;
end
elseif ChapterURL ~= nil and ChapterURL ~= "" then
Chapter = Chapter .. " " .. externallink( ChapterURL ) ..
TransError;
else
Chapter = Chapter .. TransError;
end
Chapter = Chapter .. sepc .. " " -- with end-space
elseif ChapterURL ~= nil and ChapterURL ~= "" then
Chapter = " " .. externallink( ChapterURL ) .. sepc .. " ";
end
-- Format main title.
if ( Title and "" < Title ) then
if ( TitleLink and "" < TitleLink ) then
Title = "[[" .. TitleLink .. "|" .. Title .. "]]" end
if ( Periodical and "" < Periodical ) then
Title = substitute( cfg.message_list['quoted-title'], { Title } );
elseif ( config.CitationClass == "web"
or config.CitationClass == "news"
or config.CitationClass == "pressrelease" ) and
Chapter == "" then
Title = substitute( cfg.message_list['quoted-title'], { Title } );
else
Title = substitute( cfg.message_list['italic-title'], { (safeforitalics(Title)) } );
end
else
Title = "";
end
local TransError = "";
if TransTitle ~= "" and Title == "" then
TransError = " " .. seterror( 'trans_missing_title' );
end
Title = Title .. TransTitle
if Title ~= "" then
if ( TitleLink == nil and URL and "" < URL ) then
Title = externallink( URL, Title ) .. TransError .. Format
URL = nil
Format = ''
else
Title = Title .. TransError;
end
end
if ( Place ~= nil and Place ~= "" ) then
if sepc == '.' then
Place = " " .. substitute( cfg.message_list['written'], {Place} ) .. sepc .. " ";
else
Place = " " .. substitute( cfg.message_list['written']:lower(), {Place} ) .. sepc .. " ";
end
else
Place = "";
end
if ( Conference ~= nil and Conference ~="" ) then
if ( ConferenceURL ~= nil ) then
Conference = externallink( ConferenceURL, Conference );
end
Conference = " " .. Conference
elseif ConferenceURL ~= nil and ConferenceURL ~= "" then
Conference = " " .. externallink( ConferenceURL );
else
Conference = ""
end
if ( nil ~= Position or nil ~= Page or nil ~= Pages ) then At = nil end
if ( nil == Position and "" ~= Position ) then
local Minutes = A['Minutes'];
if ( nil ~= Minutes ) then
Position = " " .. Minutes .. " " .. cfg.message_list['minutes'];
else
local Time = A['Time'];
if ( nil ~= Time ) then
local TimeCaption = A['TimeCaption']
if TimeCaption == nil then
TimeCaption = cfg.message_list['event'];
if sepc ~= '.' then
TimeCaption = TimeCaption:lower();
end
end
Position = " " .. TimeCaption .. " " .. Time
else
Position = ""
end
end
else
Position = " " .. Position
end
if ( nil == Page or "" == Page ) then
Page = ""
if ( nil == Pages or "" == Pages) then
Pages = ""
elseif ( Periodical ~= nil and Periodical ~= "" and
config.CitationClass ~= "encyclopaedia" and
config.CitationClass ~= "web" and
config.CitationClass ~= "book" and
config.CitationClass ~= "news") then
Pages = ": " .. Pages
else
if ( tonumber(Pages) ~= nil ) then
Pages = sepc .." " .. PPrefix .. Pages
else Pages = sepc .." " .. PPPrefix .. Pages
end
end
else
Pages = ""
if ( Periodical ~= nil and Periodical ~= "" and
config.CitationClass ~= "encyclopaedia" and
config.CitationClass ~= "web" and
config.CitationClass ~= "book" and
config.CitationClass ~= "news") then
Page = ": " .. Page
else
Page = sepc .." " .. PPrefix .. Page
end
end
if ( At ~= nil and At ~="") then At = sepc .. " " .. At
else At = "" end
if ( Coauthors == nil ) then Coauthors = "" end
if ( Others ~= nil and Others ~="" ) then
Others = sepc .. " " .. Others else Others = "" end
if ( TitleType ~= nil and TitleType ~="" ) then
TitleType = " (" .. TitleType .. ")" else TitleType = "" end
if ( TitleNote ~= nil and TitleNote ~="" ) then
TitleNote = sepc .. " " .. TitleNote else TitleNote = "" end
if ( Language ~= nil and Language ~="" ) then
Language = " " .. substitute( cfg.message_list['language'] , {Language} ) else Language = "" end
if ( Edition ~= nil and Edition ~="" ) then
Edition = " " .. substitute( cfg.message_list['edition'] , {Edition} ) else Edition = "" end
if ( Volume ~= nil and Volume ~="" )
then
if ( mw.ustring.len(Volume) > 4 )
then Volume = sepc .." " .. Volume
else Volume = " <b>" .. hyphentodash(Volume) .. "</b>"
end
else Volume = "" end
if ( Issue ~= nil and Issue ~="" ) then
Issue = " (" .. Issue .. ")" else Issue = "" end
if ( Series ~= nil and Series ~="" ) then
Series = sepc .. " " .. Series else Series = "" end
if ( OrigYear ~= nil and OrigYear ~="" ) then
OrigYear = " [" .. OrigYear .. "]" else OrigYear = "" end
if ( Agency ~= nil and Agency ~="" ) then
Agency = sepc .. " " .. Agency else Agency = "" end
------------------------------------ totally unrelated data
if ( Date ~= nil ) then Date = Date else Date = "" end
if ( Via ~= nil and Via ~="" ) then
Via = " " .. substitute( cfg.message_list['via'], {Via} ) else Via = "" end
if ( AccessDate ~= nil and AccessDate ~="" )
then local retrv_text = " " .. cfg.message_list['retrieved']
if (sepc ~= ".") then retrv_text = retrv_text:lower() end
AccessDate = '<span class="reference-accessdate">' .. sepc
.. substitute( retrv_text, {AccessDate} ) .. '</span>'
else AccessDate = "" end
if ( SubscriptionRequired ~= nil and
SubscriptionRequired ~= "" ) then
SubscriptionRequired = sepc .. " " .. cfg.message_list['subscription'];
else
SubscriptionRequired = ""
end
if ( ID ~= nil and ID ~="") then ID = sepc .." ".. ID else ID="" end
ID_list = buildidlist( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN} );
if ( URL ~= nil and URL ~="") then
URL = " " .. externallink( URL, URL );
local error_text = seterror( 'bare_url_missing_title' );
if config.CitationClass == "web" then
URL = URL .. " " .. seterror( 'cite_web_title' );
else
URL = URL .. error_text;
end
else
URL = ""
end
if ( Quote and Quote ~="" ) then
if Quote:sub(1,1) == '"' and Quote:sub(-1,-1) == '"' then
Quote = Quote:sub(2,-2);
end
Quote = sepc .." " .. substitute( cfg.message_list['quoted-text'], { Quote } );
PostScript = ""
else
if ( PostScript == nil) then PostScript = "" end
Quote = ""
end
local Archived
if ( nil ~= ArchiveURL and "" ~= ArchiveURL ) then
if ( ArchiveDate == nil or ArchiveDate =="" ) then
ArchiveDate = seterror('archive_missing_date');
end
if ( "no" == DeadURL ) then
local arch_text = cfg.message_list['archived'];
if (sepc ~= ".") then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( cfg.message_list['archived-not-dead'],
{ externallink( ArchiveURL, arch_text ), ArchiveDate } );
if OriginalURL == nil or OriginalUrl == '' then
Archived = Archived .. " " .. seterror('archive_missing_url');
end
else
if OriginalURL ~= nil and OriginalURL ~= '' then
local arch_text = cfg.message_list['archived-dead'];
if (sepc ~= ".") then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( arch_text,
{ externallink( OriginalURL, cfg.message_list['original'] ), ArchiveDate } );
else
local arch_text = cfg.message_list['archived-missing'];
if (sepc ~= ".") then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( arch_text,
{ seterror('archive_missing_url'), ArchiveDate } );
end
end
else
Archived = ""
end
local Lay
if ( nil ~= LaySummary and "" ~= LaySummary ) then
if ( LayDate ~= nil ) then LayDate = " (" .. LayDate .. ")" else LayDate = "" end
if ( LaySource ~= nil ) then
LaySource = " – ''" .. safeforitalics(LaySource) .. "''"
else
LaySource = ""
end
if sepc == '.' then
Lay = sepc .. " [" .. LaySummary .. " " .. cfg.message_list['lay summary'] .. "]" .. LaySource .. LayDate
else
Lay = sepc .. " [" .. LaySummary .. " " .. cfg.message_list['lay summary']:lower() .. "]" .. LaySource .. LayDate
end
else
Lay = ""
end
if ( nil ~= Transcript and "" ~= Transcript ) then
if ( TranscriptURL ~= nil ) then Transcript = externallink( TranscriptURL, Transcript ) end
elseif TranscriptURL ~= nil and TranscriptURL ~= "" then
Transcript = externallink( TranscriptURL )
else
Transcript = ""
end
local Publisher = ""
if ( Periodical and Periodical ~= "" and
config.CitationClass ~= "encyclopaedia" and
config.CitationClass ~= "web" and
config.CitationClass ~= "pressrelease" ) then
if ( PublisherName ~= nil and PublisherName ~="" ) then
if (PublicationPlace ~= nil and PublicationPlace ~= '') then
Publisher = PublicationPlace .. ": " .. PublisherName;
else
Publisher = PublisherName;
end
elseif (PublicationPlace ~= nil and PublicationPlace ~= '') then
Publisher= PublicationPlace;
else
Publisher = "";
end
if ( PublicationDate and PublicationDate ~="" ) then
if Publisher ~= '' then
Publisher = Publisher .. ", " .. substitute( cfg.message_list['published'], {PublicationDate} );
else
Publisher = PublicationDate;
end
end
if Publisher ~= "" then
Publisher = " (" .. Publisher .. ")";
end
else
if ( PublicationDate and PublicationDate ~="" ) then
PublicationDate = " (" .. substitute( cfg.message_list['published'], {PublicationDate} ) .. ")"
else
PublicationDate = ""
end
if ( PublisherName ~= nil and PublisherName ~="" ) then
if (PublicationPlace ~= nil and PublicationPlace ~= '') then
Publisher = sepc .. " " .. PublicationPlace .. ": " .. PublisherName .. PublicationDate;
else
Publisher = sepc .. " " .. PublisherName .. PublicationDate;
end
elseif (PublicationPlace ~= nil and PublicationPlace ~= '') then
Publisher= sepc .. " " .. PublicationPlace .. PublicationDate;
else
Publisher = PublicationDate;
end
end
-- Several of the above rely upon detecting this as nil, so do it last.
if ( Periodical ~= nil and Periodical ~="" ) then
if ( Title and Title ~= "" ) or ( TitleNote and TitleNote ~= "" ) then
Periodical = sepc .. " " .. substitute( cfg.message_list['italic-title'], { (safeforitalics(Periodical)) } )
else
Periodical = substitute( cfg.message_list['italic-title'], { (safeforitalics(Periodical)) } )
end
else Periodical = "" end
-- Piece all bits together at last. Here, all should be non-nil.
-- We build things this way because it is more efficient in LUA
-- not to keep reassigning to the same string variable over and over.
local tcommon
if ( ( (config.CitationClass == "journal") or (config.CitationClass == "citation") ) and
Periodical ~= "" ) then
if (Others ~= "") then Others = Others .. sepc .. " " end
tcommon = safejoin( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series,
Language, Edition, Publisher, Agency, Volume, Issue, Position}, sepc );
else
tcommon = safejoin( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language,
Volume, Issue, Others, Edition, Publisher, Agency, Position}, sepc );
end
if #ID_list > 0 then
ID_list = safejoin( { sepc .. " ", table.concat( ID_list, sepc .. " " ), ID }, sepc );
else
ID_list = ID;
end
local idcommon = safejoin( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
local text
local pgtext = Page .. Pages .. At
if ( "" ~= Authors ) then
if (Coauthors ~= "")
then Authors = Authors .. A['AuthorSeparator'] .. " " .. Coauthors
end
if ( "" ~= Date )
then Date = " ("..Date..")" .. OrigYear .. sepc .. " "
else
if ( string.sub(Authors,-1,-1) == sepc) --check end character
then Authors = Authors .. " "
else Authors = Authors .. sepc .. " "
end
end
if ( "" ~= Editors) then
local in_text = " in "
if (sepc == '.') then in_text = " In " end
if (string.sub(Editors,-1,-1) == sepc)
then Editors = in_text .. Editors .. " "
else Editors = in_text .. Editors .. sepc .. " "
end
end
text = safejoin( {Authors, Date, Chapter, Place, Editors, tcommon }, sepc );
text = safejoin( {text, pgtext, idcommon}, sepc );
elseif ( "" ~= Editors) then
if ( "" ~= Date ) then
if EditorCount <= 1 then
Editors = Editors .. ", " .. cfg.message_list['editor'];
else
Editors = Editors .. ", " .. cfg.message_list['editors'];
end
Date = " (" .. Date ..")" .. OrigYear .. sepc .. " "
else
if EditorCount <= 1 then
Editors = Editors .. " (" .. cfg.message_list['editor'] .. ")" .. sepc .. " "
else
Editors = Editors .. " (" .. cfg.message_list['editors'] .. ")" .. sepc .. " "
end
end
text = safejoin( {Editors, Date, Chapter, Place, tcommon}, sepc );
text = safejoin( {text, pgtext, idcommon}, sepc );
else
if ( "" ~= Date ) then
if ( string.sub(tcommon,-1,-1) ~= sepc )
then Date = sepc .." " .. Date .. OrigYear
else Date = " " .. Date .. OrigYear
end
end -- endif ""~=Date
if ( config.CitationClass=="journal" and Periodical ) then
text = safejoin( {Chapter, Place, tcommon}, sepc );
text = safejoin( {text, pgtext, Date, idcommon}, sepc );
else
text = safejoin( {Chapter, Place, tcommon, Date}, sepc );
text = safejoin( {text, pgtext, idcommon}, sepc );
end
end
if PostScript ~= '' and PostScript ~= nil and PostScript ~= sepc then
text = safejoin( {text, sepc}, sepc ); --Deals with italics, spaces, etc.
text = text:sub(1,-2); --Remove final seperator
end
text = safejoin( {text, PostScript}, sepc );
-- Now enclose the whole thing in a <span/> element
if ( Year == nil ) then
if ( DateIn ~= nil and DateIn ~= "" ) then
Year = selectyear( DateIn )
elseif( PublicationDate ~= nil and PublicationDate ~= "" ) then
Year = selectyear( PublicationDate )
else
Year = ""
end
end
local classname = "citation"
if ( config.CitationClass ~= "citation" )
then classname = "citation " .. (config.CitationClass or "") end
local options = { class=classname }
if ( Ref ~= nil ) then
local id = Ref
if ( "harv" == Ref ) then
local names = {} --table of last names & year
if ( "" ~= Authors ) then
for i,v in ipairs(a) do
names[i] = v.last
if i == 4 then break end
end
elseif ( "" ~= Editors ) then
for i,v in ipairs(e) do
names[i] = v.last
if i == 4 then break end
end
end
names[ #names + 1 ] = Year;
id = anchorid(names)
end
options.id = id;
end
if string.len(text:gsub("<span[^>/]*>.-</span>", ""):gsub("%b<>","")) <= 2 then
z.error_categories = {};
text = seterror('empty_citation');
z.message_tail = {};
end
if options.id ~= nil then
text = '<span id="' .. wikiescape(options.id) ..'" class="' .. wikiescape(options.class) .. '">' .. text .. "</span>";
else
text = '<span class="' .. wikiescape(options.class) .. '">' .. text .. "</span>";
end
local empty_span = '<span style="display:none;"> </span>';
-- Note: Using display: none on then COinS span breaks some clients.
local OCinS = '<span title="' .. wikiescape(OCinStitle) .. '" class="Z3988">' .. empty_span .. '</span>';
text = text .. OCinS;
if #z.message_tail ~= 0 then
text = text .. " ";
for i,v in ipairs( z.message_tail ) do
if v[1] ~= nil and v[1] ~= "" then
if i == #z.message_tail then
text = text .. errorcomment( v[1], v[2] );
else
text = text .. errorcomment( v[1] .. "; ", v[2] );
end
end
end
end
if no_tracking_cats == nil then
for _, v in ipairs( z.error_categories ) do
text = text .. '[[Category:' .. v ..']]';
end
end
return text
end
-- This is used by templates such as {{cite book}} to create the actual citation text.
function z.citation(frame)
local pframe = frame:getParent()
local args = {};
local suggestions = {};
local error_text, error_state;
for k, v in pairs( pframe.args ) do
if v ~= '' then
if not validate( k ) then
error_text = "";
if type( k ) ~= 'string' then
-- Exclude empty numbered parameters
if v:match("%S+") ~= nil then
error_text, error_state = seterror( 'text_ignored', {v}, true );
end
elseif validate( k:lower() ) then
error_text, error_state = seterror( 'parameter_ignored_suggest', {k, k:lower()}, true );
else
if #suggestions == 0 then
suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions' );
end
if suggestions[ k:lower() ] ~= nil then
error_text, error_state = seterror( 'parameter_ignored_suggest', {k, suggestions[ k:lower() ]}, true );
else
error_text, error_state = seterror( 'parameter_ignored', {k}, true );
end
end
if error_text ~= '' then
table.insert( z.message_tail, {error_text, error_state} );
end
end
args[k] = v;
elseif k == 'postscript' then
args[k] = v;
end
end
local config = {};
for k, v in pairs( frame.args ) do
config[k] = v;
if args[k] == nil and (v ~= '' or k == 'postscript') then
args[k] = v;
end
end
return citation0( config, args)
end
return z