Module:Citation/CS1: Difference between revisions
Jump to navigation
Jump to search
(sync to sandbox, mostly translation handles almost uniformity for archiveurl errors.) |
(sync with sandbox, merge cite_web_title to bare_url, better style control on translations, category suppression by config, tweak display authors) |
||
Line 28: | Line 28: | ||
message = message:sub(1,-2); | message = message:sub(1,-2); | ||
return message; | return message; | ||
end | |||
-- Wraps a string using a message_list configuration taking one argument | |||
function wrap( message_key, str ) | |||
if str == nil or str == "" then | |||
return ""; | |||
end | |||
if message_key == 'italic-title' or | |||
message_key == 'trans-italic-title' then | |||
str = safeforitalics( str ); | |||
end | |||
return substitute( cfg.message_list[message_key], {str} ); | |||
end | end | ||
Line 89: | Line 101: | ||
function errorcomment( content, hidden ) | function errorcomment( content, hidden ) | ||
if hidden then | if hidden then | ||
return | return wrap( 'hidden-error', content ); | ||
else | else | ||
return | return wrap( 'visible-error', content ); | ||
end | end | ||
end | end | ||
Line 462: | Line 474: | ||
local text = {} | local text = {} | ||
local etal = false; | local etal = false; | ||
if maximum < 1 then return "", 0; end | |||
for i,person in ipairs(people) do | for i,person in ipairs(people) do | ||
if (person.last ~= nil or person.last ~= "") then | if (person.last ~= nil or person.last ~= "") then | ||
local mask = person.mask | local mask = person.mask | ||
local one | local one | ||
if ( maximum ~= nil and i | local sep_one = sep; | ||
if ( maximum ~= nil and i > maximum ) then | |||
etal = true; | etal = true; | ||
break; | break; | ||
Line 474: | Line 488: | ||
one = string.rep("—",n) | one = string.rep("—",n) | ||
else | else | ||
one = mask | one = mask; | ||
sep_one = " "; | |||
end | end | ||
else | else | ||
Line 485: | Line 500: | ||
if (person.link ~= nil and person.link ~= "") then one = "[[" .. person.link .. "|" .. one .. "]]" end | if (person.link ~= nil and person.link ~= "") then one = "[[" .. person.link .. "|" .. one .. "]]" end | ||
end | end | ||
table.insert(text, one) | table.insert( text, one ) | ||
table.insert( text, sep_one ) | |||
end | |||
end | |||
local count = #text / 2; | |||
if count > 0 then | |||
if count > 1 and lastauthoramp ~= nil and lastauthoramp ~= "" and not etal then | |||
text[#text-2] = " & "; | |||
end | end | ||
text[#text] = nil; | |||
end | end | ||
local result = table.concat(text) -- construct list | |||
local result = table.concat(text | |||
if etal then | if etal then | ||
local etal_text = cfg.message_list['et al']; | local etal_text = cfg.message_list['et al']; | ||
Line 770: | Line 790: | ||
local sepc = A['Separator'] | local sepc = A['Separator'] | ||
local LastAuthorAmp = A['LastAuthorAmp'] | local LastAuthorAmp = A['LastAuthorAmp'] | ||
local no_tracking_cats = A['NoTracking']; | local no_tracking_cats = A['NoTracking'] or ""; | ||
local this_page = mw.title.getCurrentTitle(); --Also used for COinS | |||
if no_tracking_cats == "" then | |||
for k, v in pairs( cfg.uncategorized_namespaces ) do | |||
if this_page.nsText == v then | |||
no_tracking_cats = "true"; | |||
break; | |||
end | |||
end | |||
end | |||
if ( config.CitationClass == "journal" ) then | if ( config.CitationClass == "journal" ) then | ||
Line 908: | Line 938: | ||
end | end | ||
OCinStitle = OCinStitle .. "&rfr_id=info:sid/" .. mw.site.server:match( "[^/]*$" ) .. ":" | OCinStitle = OCinStitle .. "&rfr_id=info:sid/" .. mw.site.server:match( "[^/]*$" ) .. ":" | ||
.. this_page.prefixedText -- end COinS data by page's non-encoded pagename | .. this_page.prefixedText -- end COinS data by page's non-encoded pagename | ||
Line 1,061: | Line 1,090: | ||
end | end | ||
-- Format chapter / article title | -- Format chapter / article title | ||
if ( Chapter ~= nil and Chapter ~= "" ) | if ( Chapter ~= nil and Chapter ~= "" ) and ( ChapterLink and "" < ChapterLink ) then | ||
Chapter = "[[" .. ChapterLink .. "|" .. Chapter .. "]]"; | |||
end | |||
if ( Periodical and "" < Periodical ) and (Title ~= nil and Title ~= "" ) then | |||
Chapter = wrap( 'italic-title', Chapter ); | |||
TransChapter = wrap( 'trans-italic-title', TransChapter ); | |||
else | else | ||
Chapter = | Chapter = wrap( 'quoted-title', Chapter ); | ||
TransChapter = wrap( 'trans-quoted-title', TransChapter ); | |||
end | end | ||
Line 1,081: | Line 1,106: | ||
TransError = " " .. seterror( 'trans_missing_chapter' ); | TransError = " " .. seterror( 'trans_missing_chapter' ); | ||
end | end | ||
if TransChapter ~= "" and Chapter ~= "" then TransChapter = " " .. TransChapter; end | |||
Chapter = Chapter .. TransChapter | Chapter = Chapter .. TransChapter | ||
if Chapter ~= "" then | if Chapter ~= "" then | ||
if ( ChapterLink == nil ) then | if ( ChapterLink == nil ) then | ||
Line 1,109: | Line 1,137: | ||
-- Format main title. | -- Format main title. | ||
if ( | if ( TitleLink and "" < TitleLink ) then | ||
if ( | if ( Title and "" < Title ) then | ||
Title = "[[" .. TitleLink .. "|" .. Title .. "]]" | Title = "[[" .. TitleLink .. "|" .. Title .. "]]" | ||
end | end | ||
end | |||
if ( Periodical and "" < Periodical ) then | |||
Title = wrap( 'quoted-title', Title ); | |||
TransTitle = wrap( 'trans-quoted-title', TransTitle ); | |||
elseif ( config.CitationClass == "web" | |||
or config.CitationClass == "news" | |||
or config.CitationClass == "pressrelease" ) and | |||
Chapter == "" then | |||
Title = wrap( 'quoted-title', Title ); | |||
TransTitle = wrap( 'trans-quoted-title', TransTitle ); | |||
else | else | ||
Title = | Title = wrap( 'italic-title', Title ); | ||
end | TransTitle = wrap( 'trans-italic-title', TransTitle ); | ||
end | |||
local TransError = ""; | local TransError = ""; | ||
Line 1,130: | Line 1,161: | ||
TransError = " " .. seterror( 'trans_missing_title' ); | TransError = " " .. seterror( 'trans_missing_title' ); | ||
end | end | ||
if TransTitle ~= "" and Title ~= "" then TransTitle = " " .. TransTitle; end | |||
Title = Title .. TransTitle | Title = Title .. TransTitle | ||
if Title ~= "" then | if Title ~= "" then | ||
if ( TitleLink == nil and URL and "" < URL ) then | if ( TitleLink == nil and URL and "" < URL ) then | ||
Line 1,143: | Line 1,177: | ||
if ( Place ~= nil and Place ~= "" ) then | if ( Place ~= nil and Place ~= "" ) then | ||
if sepc == '.' then | if sepc == '.' then | ||
Place = " " .. | Place = " " .. wrap( 'written', Place ) .. sepc .. " "; | ||
else | else | ||
Place = " " .. substitute( cfg.message_list['written']:lower(), {Place} ) .. sepc .. " "; | Place = " " .. substitute( cfg.message_list['written']:lower(), {Place} ) .. sepc .. " "; | ||
Line 1,222: | Line 1,256: | ||
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 = " " .. wrap( 'language', Language ) else Language = "" end | ||
if ( Edition ~= nil and Edition ~="" ) then | if ( Edition ~= nil and Edition ~="" ) then | ||
Edition = " " .. | Edition = " " .. wrap( 'edition', Edition ) else Edition = "" end | ||
if ( Volume ~= nil and Volume ~="" ) | if ( Volume ~= nil and Volume ~="" ) | ||
then | then | ||
Line 1,243: | Line 1,277: | ||
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 = " " .. wrap( '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'] | ||
Line 1,261: | Line 1,295: | ||
if ( URL ~= nil and URL ~="") then | if ( URL ~= nil and URL ~="") then | ||
URL = " " .. externallink( | URL = " " .. externallink( URL ); | ||
else | else | ||
URL = "" | URL = "" | ||
Line 1,277: | Line 1,305: | ||
end | end | ||
Quote = sepc .." " .. | Quote = sepc .." " .. wrap( 'quoted-text', Quote ); | ||
PostScript = "" | PostScript = "" | ||
else | else | ||
Line 1,322: | Line 1,350: | ||
end | end | ||
if sepc == '.' then | if sepc == '.' then | ||
Lay = sepc .. " | Lay = sepc .. " " .. externallink( LaySummary, cfg.message_list['lay summary'] ) .. LaySource .. LayDate | ||
else | else | ||
Lay = sepc .. " | Lay = sepc .. " " .. externallink( LaySummary, cfg.message_list['lay summary']:lower() ) .. LaySource .. LayDate | ||
end | end | ||
else | else | ||
Line 1,354: | Line 1,382: | ||
if ( PublicationDate and PublicationDate ~="" ) then | if ( PublicationDate and PublicationDate ~="" ) then | ||
if Publisher ~= '' then | if Publisher ~= '' then | ||
Publisher = Publisher .. ", " .. | Publisher = Publisher .. ", " .. wrap( 'published', PublicationDate ); | ||
else | else | ||
Publisher = PublicationDate; | Publisher = PublicationDate; | ||
Line 1,364: | Line 1,392: | ||
else | else | ||
if ( PublicationDate and PublicationDate ~="" ) then | if ( PublicationDate and PublicationDate ~="" ) then | ||
PublicationDate = " (" .. | PublicationDate = " (" .. wrap( 'published', PublicationDate ) .. ")" | ||
else | else | ||
PublicationDate = "" | PublicationDate = "" | ||
Line 1,383: | Line 1,411: | ||
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 .. " " .. wrap( 'italic-title', Periodical ) | ||
else | else | ||
Periodical = | Periodical = wrap( 'italic-title', Periodical ) | ||
end | end | ||
else Periodical = "" end | else Periodical = "" end | ||
Line 1,542: | Line 1,570: | ||
end | end | ||
if no_tracking_cats == | no_tracking_cats = no_tracking_cats:lower(); | ||
if no_tracking_cats == "" or no_tracking_cats == "no" or | |||
no_tracking_cats == "false" or no_tracking_cats == "n" 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 ..']]'; |
Revision as of 23:07, 19 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 -- Wraps a string using a message_list configuration taking one argument function wrap( message_key, str ) if str == nil or str == "" then return ""; end if message_key == 'italic-title' or message_key == 'trans-italic-title' then str = safeforitalics( str ); end return substitute( cfg.message_list[message_key], {str} ); 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 wrap( 'hidden-error', content ); else return wrap( '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; if maximum < 1 then return "", 0; end for i,person in ipairs(people) do if (person.last ~= nil or person.last ~= "") then local mask = person.mask local one local sep_one = sep; if ( maximum ~= nil and i > maximum ) then etal = true; break; elseif (mask ~= nil) then local n = tonumber(mask) if (n ~= nil) then one = string.rep("—",n) else one = mask; sep_one = " "; 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 ) table.insert( text, sep_one ) end end local count = #text / 2; if count > 0 then if count > 1 and lastauthoramp ~= nil and lastauthoramp ~= "" and not etal then text[#text-2] = " & "; end text[#text] = nil; end local result = table.concat(text) -- 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'] or ""; local this_page = mw.title.getCurrentTitle(); --Also used for COinS if no_tracking_cats == "" then for k, v in pairs( cfg.uncategorized_namespaces ) do if this_page.nsText == v then no_tracking_cats = "true"; break; end end end 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 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 -- Format chapter / article title if ( Chapter ~= nil and Chapter ~= "" ) and ( ChapterLink and "" < ChapterLink ) then Chapter = "[[" .. ChapterLink .. "|" .. Chapter .. "]]"; end if ( Periodical and "" < Periodical ) and (Title ~= nil and Title ~= "" ) then Chapter = wrap( 'italic-title', Chapter ); TransChapter = wrap( 'trans-italic-title', TransChapter ); else Chapter = wrap( 'quoted-title', Chapter ); TransChapter = wrap( 'trans-quoted-title', TransChapter ); end local TransError = "" if TransChapter ~= "" and Chapter == "" then TransError = " " .. seterror( 'trans_missing_chapter' ); end if TransChapter ~= "" and Chapter ~= "" then TransChapter = " " .. TransChapter; 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 ( TitleLink and "" < TitleLink ) then if ( Title and "" < Title ) then Title = "[[" .. TitleLink .. "|" .. Title .. "]]" end end if ( Periodical and "" < Periodical ) then Title = wrap( 'quoted-title', Title ); TransTitle = wrap( 'trans-quoted-title', TransTitle ); elseif ( config.CitationClass == "web" or config.CitationClass == "news" or config.CitationClass == "pressrelease" ) and Chapter == "" then Title = wrap( 'quoted-title', Title ); TransTitle = wrap( 'trans-quoted-title', TransTitle ); else Title = wrap( 'italic-title', Title ); TransTitle = wrap( 'trans-italic-title', TransTitle ); end local TransError = ""; if TransTitle ~= "" and Title == "" then TransError = " " .. seterror( 'trans_missing_title' ); end if TransTitle ~= "" and Title ~= "" then TransTitle = " " .. TransTitle; 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 = " " .. wrap( '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 = " " .. wrap( 'language', Language ) else Language = "" end if ( Edition ~= nil and Edition ~="" ) then Edition = " " .. wrap( '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 = " " .. wrap( '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 ); 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 .." " .. wrap( '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 .. " " .. externallink( LaySummary, cfg.message_list['lay summary'] ) .. LaySource .. LayDate else Lay = sepc .. " " .. externallink( 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 .. ", " .. wrap( 'published', PublicationDate ); else Publisher = PublicationDate; end end if Publisher ~= "" then Publisher = " (" .. Publisher .. ")"; end else if ( PublicationDate and PublicationDate ~="" ) then PublicationDate = " (" .. wrap( '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 .. " " .. wrap( 'italic-title', Periodical ) else Periodical = wrap( 'italic-title', 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 no_tracking_cats = no_tracking_cats:lower(); if no_tracking_cats == "" or no_tracking_cats == "no" or no_tracking_cats == "false" or no_tracking_cats == "n" 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