Module:Citation/CS1: Difference between revisions
Synch from sandbox;
m>Shyamal |
m>Trappist the monk (Synch from sandbox;) |
||
Line 167: | Line 167: | ||
the URI scheme is valid or whether the URL is otherwise well formed. | the URI scheme is valid or whether the URL is otherwise well formed. | ||
The scheme is checked http://tools.ietf.org/html/std66#section-3.1 which says: | |||
Scheme names consist of a sequence of characters beginning with a | |||
letter and followed by any combination of letters, digits, plus | |||
("+"), period ("."), or hyphen ("-"). | |||
First we test for space characters. If any are found, return false. Then test for the case where the url is | |||
protocol relative (//example.com). If the first two characters of the |url= value are //, return true. Last | |||
look for what appears to be a scheme according to the definition above. If the characters preceding the colon | |||
are in the allowed set, return true, else false | |||
]] | ]] | ||
local function check_url( url_str ) | local function check_url( url_str ) | ||
return url_str:sub(1,2) == "//" or url_str:match( "^[ | if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value | ||
return false; | |||
end | |||
return url_str:sub(1,2) == "//" or nil ~= url_str:match ("^%a[%a%d%+%.%-]*:") -- protocol relative or scheme part composed of legitimate characters | |||
end | end | ||
Line 334: | Line 346: | ||
is not added. At this time there is no error message for this condition. | is not added. At this time there is no error message for this condition. | ||
Supports |script-title= and |script-chapter= | |||
TODO: error messages when prefix is invalid ISO639-1 code; when script_value has prefix but no script; | TODO: error messages when prefix is invalid ISO639-1 code; when script_value has prefix but no script; | ||
Line 352: | Line 364: | ||
script_value = script_value:gsub ('^%l%l%s*:%s*', ''); -- strip prefix from script | script_value = script_value:gsub ('^%l%l%s*:%s*', ''); -- strip prefix from script | ||
-- is prefix one of these language codes? | -- is prefix one of these language codes? | ||
if in_array (lang, {'ar', 'bg', 'bs', 'dv', 'el', 'fa', 'hy', 'ja', 'ka', 'ko', 'ku', ' | if in_array (lang, {'ar', 'bg', 'bs', 'dv', 'el', 'fa', 'he', 'hy', 'ja', 'ka', 'ko', 'ku', 'mk', 'ps', 'ru', 'sd', 'sr', 'th', 'uk', 'ug', 'yi', 'zh'}) then | ||
add_prop_cat ('script_with_name', {name, lang}) | add_prop_cat ('script_with_name', {name, lang}) | ||
else | else | ||
Line 469: | Line 481: | ||
--[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >-------------------------------------- | --[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >-------------------------------------- | ||
Format the | Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single Chapter meta- | ||
parameter (chapter_url_source used for error messages). | parameter (chapter_url_source used for error messages). | ||
]] | ]] | ||
local function format_chapter_title (chapter, transchapter, chapterurl, chapter_url_source) | local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source) | ||
local chapter_error = ''; | local chapter_error = ''; | ||
if not is_set (chapter) then | if not is_set (chapter) then | ||
chapter = ''; -- | chapter = ''; -- to be safe for concatenation | ||
else | |||
else | |||
chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks | chapter = kern_quotes (chapter); -- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks | ||
chapter = wrap_style ('quoted-title', chapter); | chapter = wrap_style ('quoted-title', chapter); | ||
end | |||
chapter = chapter .. ' ' .. transchapter; | chapter = script_concatenate (chapter, scriptchapter) -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped | ||
if is_set (transchapter) then | |||
transchapter = wrap_style ('trans-quoted-title', transchapter); | |||
if is_set (chapter) then | |||
chapter = chapter .. ' ' .. transchapter; | |||
else -- here when transchapter without chapter or script-chapter | |||
chapter = transchapter; -- | |||
chapter_error = ' ' .. set_error ('trans_missing_title', {'chapter'}); | |||
end | end | ||
end | end | ||
return chapter; | |||
if is_set (chapterurl) then | |||
chapter = external_link (chapterurl, chapter, chapter_url_source); -- adds bare_url_missing_title error if appropriate | |||
end | |||
return chapter .. chapter_error; | |||
end | end | ||
--[[ | --[[ | ||
Line 706: | Line 721: | ||
-- prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) | -- prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode}) | ||
text="[[" .. handler.link .. "|" .. handler.label .. "]] | text="[[" .. handler.link .. "|" .. handler.label .. "]]" .. handler.separator .. id; -- because no place to link to yet | ||
if false == valid_ismn then | if false == valid_ismn then | ||
Line 791: | Line 806: | ||
end | end | ||
local handler = cfg.id_handlers['ASIN']; | local handler = cfg.id_handlers['ASIN']; | ||
return external_link_id({link = handler.link, | return external_link_id({link=handler.link, | ||
label=handler.label , prefix= | label=handler.label, prefix=handler.prefix .. domain .. "/dp/", | ||
id=id, encode=handler.encode, separator = handler.separator}) .. err_cat; | |||
end | end | ||
Line 1,093: | Line 1,108: | ||
if ( code == "A" ) then | if ( code == "A" ) then | ||
return external_link_id({link=handler.link, label=handler.label, | return external_link_id({link=handler.link, label=handler.label, | ||
prefix= | prefix=handler.prefix .. 'authors/OL', | ||
id=id, separator=handler.separator, encode = handler.encode}) | |||
elseif ( code == "M" ) then | elseif ( code == "M" ) then | ||
return external_link_id({link=handler.link, label=handler.label, | return external_link_id({link=handler.link, label=handler.label, | ||
prefix= | prefix=handler.prefix .. 'books/OL', | ||
id=id, separator=handler.separator, encode = handler.encode}) | |||
elseif ( code == "W" ) then | elseif ( code == "W" ) then | ||
return external_link_id({link=handler.link, label=handler.label, | return external_link_id({link=handler.link, label=handler.label, | ||
prefix= | prefix=handler.prefix .. 'works/OL', | ||
id=id, separator=handler.separator, encode = handler.encode}) | |||
else | else | ||
return external_link_id({link=handler.link, label=handler.label, | return external_link_id({link=handler.link, label=handler.label, | ||
prefix= | prefix=handler.prefix .. 'OL', | ||
id=id, separator=handler.separator, encode = handler.encode}) .. ' ' .. set_error( 'bad_ol' ); | |||
end | end | ||
end | end | ||
Line 1,469: | Line 1,483: | ||
local result = table.concat(text) -- construct list | local result = table.concat(text) -- construct list | ||
if etal and is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list | if etal and is_set (result) then -- etal may be set by |display-authors=etal but we might not have a last-first list | ||
result = result .. ' ' .. cfg.messages['et al']; -- we've go a last-first list and etal so add et al. | result = result .. sep .. ' ' .. cfg.messages['et al']; -- we've go a last-first list and etal so add et al. | ||
end | end | ||
Line 1,492: | Line 1,506: | ||
--[[--------------------------< N A M E _ H A S _ E T A L >---------------------------------------------------- | --[[--------------------------< N A M E _ H A S _ E T A L >---------------------------------------------------- | ||
Evaluates the content of author and editor name parameters for variations on the theme | Evaluates the content of author and editor name parameters for variations on the theme of et al. If found, | ||
the et al. is removed, a flag is set to true and the function returns the modified name and the flag. | the et al. is removed, a flag is set to true and the function returns the modified name and the flag. | ||
This function never sets the flag to false but returns it's previous state because it may have been set by | This function never sets the flag to false but returns it's previous state because it may have been set by | ||
previous passes through this function or by the parameters |display-authors=etal or | | previous passes through this function or by the parameters |display-authors=etal or |display-editors=etal | ||
]] | ]] | ||
Line 1,503: | Line 1,517: | ||
if is_set (name) then -- name can be nil in which case just return | if is_set (name) then -- name can be nil in which case just return | ||
local | local etal_pattern = "[;,]? *[\"']*%f[Ee][Ee][Tt] *[Aa][Ll][%.\"']*$" -- variations on the 'et al' theme | ||
local others_pattern = "[;,]? *%f[%a]and [Oo]thers"; -- and alternate to et al. | |||
if name:match ( | if name:match (etal_pattern) then -- variants on et al. | ||
name = name:gsub ( | name = name:gsub (etal_pattern, ''); -- if found, remove | ||
etal = true; -- set flag (may have been set previously here or by |display-authors=etal) | |||
if not nocat then -- no categorization for |vauthors= | |||
add_maint_cat ('etal'); -- and add a category if not already added | |||
end | |||
elseif name:match (others_pattern) then -- if not 'et al.', then 'and others'? | |||
name = name:gsub (others_pattern, ''); -- if found, remove | |||
etal = true; -- set flag (may have been set previously here or by |display-authors=etal) | etal = true; -- set flag (may have been set previously here or by |display-authors=etal) | ||
if not nocat then -- no categorization for |vauthors= | if not nocat then -- no categorization for |vauthors= | ||
Line 1,544: | Line 1,565: | ||
local err_msg_list_name = list_name:match ("(%w+)List") .. 's list'; -- modify AuthorList or EditorList for use in error messages if necessary | local err_msg_list_name = list_name:match ("(%w+)List") .. 's list'; -- modify AuthorList or EditorList for use in error messages if necessary | ||
while true do | while true do | ||
last = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1 | last = select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parameters', i ); -- search through args for name components beginning at 1 | ||
Line 1,650: | Line 1,670: | ||
-- COinS metadata (see <http://ocoins.info/>) allows automated tools to parse | --[[--------------------------< C O I N S >-------------------------------------------------------------------- | ||
COinS metadata (see <http://ocoins.info/>) allows automated tools to parse the citation information. | |||
]] | |||
local function COinS(data, class) | local function COinS(data, class) | ||
if 'table' ~= type(data) or nil == next(data) then | if 'table' ~= type(data) or nil == next(data) then | ||
Line 1,668: | Line 1,692: | ||
}); | }); | ||
if is_set(data. | if in_array (class, {'citation', 'conference', 'interview', 'press release'}) and is_set(data.Periodical) then | ||
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx: | OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal"; | ||
OCinSoutput["rft.genre"] = " | OCinSoutput["rft.genre"] = "article"; | ||
OCinSoutput["rft. | OCinSoutput["rft.jtitle"] = data.Periodical; | ||
OCinSoutput["rft. | OCinSoutput["rft.atitle"] = data.Title; | ||
elseif | elseif in_array (class, {'arxiv', 'journal', 'news'}) then | ||
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal"; | OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal"; | ||
if 'arxiv' == class then | if 'arxiv' == class then | ||
Line 1,684: | Line 1,708: | ||
else | else | ||
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"; | OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"; | ||
OCinSoutput["rft.genre"] = "book" | if is_set (data.Chapter) then | ||
OCinSoutput["rft.genre"] = "bookitem"; | |||
OCinSoutput["rft.atitle"] = data.Chapter; | |||
else | |||
OCinSoutput["rft.genre"] = "book" | |||
end | |||
OCinSoutput["rft.btitle"] = data.Title; | OCinSoutput["rft.btitle"] = data.Title; | ||
end | end | ||
OCinSoutput["rft.place"] = data.PublicationPlace; | OCinSoutput["rft.place"] = data.PublicationPlace; | ||
OCinSoutput["rft.date"] = data.Date; | OCinSoutput["rft.date"] = data.Date; | ||
Line 1,710: | Line 1,739: | ||
for k, v in ipairs( data.Authors ) do | for k, v in ipairs( data.Authors ) do | ||
last, first = v.last, v.first; | last, first = v.last, v.first; | ||
if k == 1 then | if k == 1 then -- for the first author name only | ||
if is_set(last) then | if is_set(last) and is_set(first) then -- set these COinS values if |first= and |last= specify the first author name | ||
OCinSoutput["rft.aulast"] = last; | OCinSoutput["rft.aulast"] = last; | ||
OCinSoutput["rft.aufirst"] = first; | |||
elseif is_set(last) then | |||
OCinSoutput["rft.au"] = last; -- otherwise use this form for the first name | |||
end | end | ||
if is_set(first) then | else -- for all other authors | ||
OCinSoutput["rft. | if is_set(last) and is_set(first) then | ||
OCinSoutput["rft.au"] = table.concat{ last, ", ", first }; | |||
elseif is_set(last) then | |||
OCinSoutput["rft.au"] = last; | |||
end | end | ||
end | end | ||
end | end | ||
OCinSoutput.rft_id = data.URL; | OCinSoutput.rft_id = data.URL; | ||
OCinSoutput.rfr_id = table.concat{ "info:sid/", mw.site.server:match( "[^/]*$" ), ":", data.RawPage }; | OCinSoutput.rfr_id = table.concat{ "info:sid/", mw.site.server:match( "[^/]*$" ), ":", data.RawPage }; | ||
Line 1,901: | Line 1,931: | ||
sep, ps = set_cs1_style (ps); | sep, ps = set_cs1_style (ps); | ||
else -- anything but cs1 or cs2 | else -- anything but cs1 or cs2 | ||
sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass | sep, ps, ref = get_settings_from_cite_class (ps, ref, cite_class); -- get settings based on the template's CitationClass | ||
end | end | ||
Line 1,915: | Line 1,942: | ||
--[=[-------------------------< I S _ P D F >------------------------------------------------------------------ | --[=[-------------------------< I S _ P D F >------------------------------------------------------------------ | ||
Determines if a url has the file extension is one of the pdf file extensions used by [[MediaWiki:Common.css]] when | Determines if a url has the file extension that is one of the pdf file extensions used by [[MediaWiki:Common.css]] when | ||
applying the pdf icon to external links. | applying the pdf icon to external links. | ||
Line 2,025: | Line 2,052: | ||
may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance | may sometimes be required and because such names will often fail the is_good_vanc_name() and other format compliance | ||
tests, are wrapped in doubled paranethese ((corporate name)) to suppress the format tests. | tests, are wrapped in doubled paranethese ((corporate name)) to suppress the format tests. | ||
This function sets the vancouver error when a reqired comma is missing and when there is a space between an author's initials. | |||
]] | ]] | ||
Line 2,051: | Line 2,080: | ||
first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be author intials | first = table.remove(lastfirstTable); -- removes and returns value of last element in table which should be author intials | ||
last = table.concat(lastfirstTable, " ") -- returns a string that is the concatenation of all other names that are not initials | last = table.concat(lastfirstTable, " ") -- returns a string that is the concatenation of all other names that are not initials | ||
if mw.ustring.match (last, '%a+%s+%u+%s+%a+') or mw.ustring.match (v_name, ' %u %u$') then | |||
add_vanc_error (); -- matches last II last; the case when a comma is missing or a space between two intiials | |||
end | |||
else | else | ||
first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor | first = ''; -- set to empty string for concatenation and because it may have been set for previous author/editor | ||
Line 2,108: | Line 2,140: | ||
if is_set (vxxxxors) then return 2 end; | if is_set (vxxxxors) then return 2 end; | ||
if is_set (xxxxors) then return 3 end; | if is_set (xxxxors) then return 3 end; | ||
return | return 1; -- no authors so return 1; this allows missing author name test to run in case there is a first without last | ||
end | end | ||
--[[--------------------------< I S _ V A L I D _ P A R A M E T E R _ V A L U E >------------------------------ | |||
This function is used to validate a parameter's assigned value for those parameters that have only a limited number | |||
of allowable values (yes, y, true, no, etc). When the parameter value has not been assigned a value (missing or empty | |||
in the source template) the function refurns true. If the parameter value is one of the list of allowed values returns | |||
true; else, emits an error message and returns false. | |||
]] | |||
local function is_valid_parameter_value (value, name, possible) | |||
if not is_set (value) then | |||
return true; -- an empty parameter is ok | |||
elseif in_array(value:lower(), possible) then | |||
return true; | |||
else | |||
table.insert( z.message_tail, { set_error( 'invalid_param_val', {name, value}, true ) } ); -- not an allowed value so add error message | |||
return false | |||
end | |||
end | |||
--[[--------------------------< I S _ P A R A M E T E R _ E X T _ W I K I L I N K >---------------------------- | |||
Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first | |||
characters following the opening bracket obey the rules of a uri scheme (see check_url()). The test will also find | |||
external wikilinks that use protocol relative urls. | |||
]] | |||
local function is_parameter_ext_wikilink (value) | |||
if value:match ("%[%a[%a%d%+%.%-]*:.*%]") or value:match ("%[//.*%]") then -- does the param value contain an external wikilink? | |||
return true; | |||
else | |||
return false; | |||
end | |||
end | |||
--[[-------------------------< C H E C K _ F O R _ U R L >----------------------------------------------------- | |||
loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message. | |||
]] | |||
local function check_for_url (parameter_list) | |||
local error_message = ''; | |||
for k, v in pairs (parameter_list) do -- for each parameter in the list | |||
if is_parameter_ext_wikilink (v) then -- look at the value; if there is a url add an error message | |||
if is_set(error_message) then -- once we've added the first portion of the error message ... | |||
error_message=error_message .. ", "; -- ... add a comma space separator | |||
end | |||
error_message=error_message .. "|" .. k .. "="; -- add the failed parameter | |||
end | |||
end | |||
if is_set (error_message) then -- done looping, if there is an error message, display it | |||
table.insert( z.message_tail, { set_error( 'param_has_ext_link', {error_message}, true ) } ); | |||
end | |||
end | |||
--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ | --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ | ||
Line 2,128: | Line 2,221: | ||
local PPPrefix = A['PPPrefix'] | local PPPrefix = A['PPPrefix'] | ||
local NoPP = A['NoPP'] | local NoPP = A['NoPP'] | ||
if | if is_valid_parameter_value (NoPP, 'nopp', cfg.keywords ['yes_true_y']) then | ||
PPPrefix = ''; -- unset these, prefix if used is in |page= or |pages= | PPPrefix = ''; -- unset these, prefix if used is in |page= or |pages= | ||
PPrefix = ''; | PPrefix = ''; | ||
Line 2,134: | Line 2,227: | ||
NoPP = nil; -- unset, used as a flag later | NoPP = nil; -- unset, used as a flag later | ||
end | 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. | ||
Line 2,140: | Line 2,233: | ||
local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= | local a = {}; -- authors list from |lastn= / |firstn= pairs or |vauthors= | ||
local Authors; | local Authors; | ||
local NameListFormat = A['NameListFormat']; | local NameListFormat = A['NameListFormat']; | ||
do -- to limit scope of selected | do -- to limit scope of selected | ||
Line 2,173: | Line 2,266: | ||
end | end | ||
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs | |||
local Translators; -- assembled trnaslators name list | |||
NameListFormat = ''; -- set to empty string | t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= | ||
if not is_valid_parameter_value (NameListFormat, 'name-list-format', cfg.keywords['name-list-format']) then -- only accepted value for this parameter is 'vanc' | |||
NameListFormat = ''; -- anything else, set to empty string | |||
end | end | ||
Line 2,192: | Line 2,288: | ||
local TitleLink = A['TitleLink']; | local TitleLink = A['TitleLink']; | ||
local Chapter = A['Chapter']; | local Chapter = A['Chapter']; | ||
local ChapterLink = A['ChapterLink']; | local ScriptChapter = A['ScriptChapter']; | ||
local ChapterLink -- = A['ChapterLink']; -- deprecated as a parameter but still used internally by cite episode | |||
local TransChapter = A['TransChapter']; | local TransChapter = A['TransChapter']; | ||
local TitleType = A['TitleType']; | local TitleType = A['TitleType']; | ||
Line 2,222: | Line 2,319: | ||
local PublisherName = A['PublisherName']; | local PublisherName = A['PublisherName']; | ||
local RegistrationRequired = A['RegistrationRequired']; | local RegistrationRequired = A['RegistrationRequired']; | ||
if not is_valid_parameter_value (RegistrationRequired, 'registration', cfg.keywords ['yes_true_y']) then | |||
registration=nil; | |||
end | |||
local SubscriptionRequired = A['SubscriptionRequired']; | local SubscriptionRequired = A['SubscriptionRequired']; | ||
if not is_valid_parameter_value (SubscriptionRequired, 'subscription', cfg.keywords ['yes_true_y']) then | |||
subscription=nil; | |||
end | |||
local Via = A['Via']; | local Via = A['Via']; | ||
local AccessDate = A['AccessDate']; | local AccessDate = A['AccessDate']; | ||
Line 2,228: | Line 2,332: | ||
local Agency = A['Agency']; | local Agency = A['Agency']; | ||
local DeadURL = A['DeadURL'] | local DeadURL = A['DeadURL'] | ||
if not is_valid_parameter_value (DeadURL, 'dead-url', cfg.keywords ['deadurl']) then -- set in config.defaults to 'yes' | |||
DeadURL = ''; -- anything else, set to empty string | |||
end | |||
local Language = A['Language']; | local Language = A['Language']; | ||
local Format = A['Format']; | local Format = A['Format']; | ||
Line 2,235: | Line 2,343: | ||
local ASINTLD = A['ASINTLD']; | local ASINTLD = A['ASINTLD']; | ||
local IgnoreISBN = A['IgnoreISBN']; | local IgnoreISBN = A['IgnoreISBN']; | ||
if not is_valid_parameter_value (IgnoreISBN, 'ignore-isbn-error', cfg.keywords ['yes_true_y']) then | |||
IgnoreISBN = nil; -- anything else, set to empty string | |||
end | |||
local Embargo = A['Embargo']; | local Embargo = A['Embargo']; | ||
local Class = A['Class']; -- arxiv class identifier | local Class = A['Class']; -- arxiv class identifier | ||
Line 2,251: | Line 2,362: | ||
local LastAuthorAmp = A['LastAuthorAmp']; | local LastAuthorAmp = A['LastAuthorAmp']; | ||
if not is_valid_parameter_value (LastAuthorAmp, 'last-author-amp', cfg.keywords ['yes_true_y']) then | |||
LastAuthorAmp = nil; -- set to empty string | |||
end | |||
local no_tracking_cats = A['NoTracking']; | local no_tracking_cats = A['NoTracking']; | ||
if not is_valid_parameter_value (no_tracking_cats, 'no-tracking', cfg.keywords ['yes_true_y']) then | |||
no_tracking_cats = nil; -- set to empty string | |||
end | |||
--these are used by cite interview | --these are used by cite interview | ||
Line 2,265: | Line 2,382: | ||
-- set default parameter values defined by |mode= parameter. If |mode= is empty or omitted, use CitationClass to set these values | -- set default parameter values defined by |mode= parameter. If |mode= is empty or omitted, use CitationClass to set these values | ||
local Mode = A['Mode']; | |||
if not is_valid_parameter_value (Mode, 'mode', cfg.keywords['mode']) then | |||
Mode = ''; | |||
end | |||
local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma | local sepc; -- separator between citation elements for CS1 a period, for CS2, a comma | ||
local PostScript; | local PostScript; | ||
local Ref; | local Ref; | ||
sepc, PostScript, Ref = set_style ( | sepc, PostScript, Ref = set_style (Mode:lower(), A['PostScript'], A['Ref'], config.CitationClass); | ||
use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text | use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text | ||
Line 2,318: | Line 2,439: | ||
All other combinations of |encyclopedia, |title, and |article are not modified | All other combinations of |encyclopedia, |title, and |article are not modified | ||
]] | ]] | ||
Line 2,324: | Line 2,445: | ||
if ( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia)) then -- test code for citation | if ( config.CitationClass == "encyclopaedia" ) or ( config.CitationClass == "citation" and is_set (Encyclopedia)) then -- test code for citation | ||
if is_set(Periodical) then | if is_set(Periodical) then -- Periodical is set when |encyclopedia is set | ||
if is_set(Title) then | if is_set(Title) or is_set (ScriptTitle) then | ||
if not is_set(Chapter) then | if not is_set(Chapter) then | ||
Chapter = Title; | Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title | ||
ScriptChapter = ScriptTitle; | |||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
ChapterURL = URL; | ChapterURL = URL; | ||
Line 2,335: | Line 2,457: | ||
Title = Periodical; | Title = Periodical; | ||
ChapterFormat = Format; | ChapterFormat = Format; | ||
Periodical = ''; | Periodical = ''; -- redundant so unset | ||
TransTitle = ''; | TransTitle = ''; | ||
URL = ''; | URL = ''; | ||
Format = ''; | Format = ''; | ||
TitleLink = ''; | TitleLink = ''; | ||
ScriptTitle = ''; | |||
end | end | ||
else | else -- |title not set | ||
Title = Periodical; | Title = Periodical; -- |encyclopedia set and |article set or not set so map |encyclopedia to |title | ||
Periodical = ''; | Periodical = ''; -- redundant so unset | ||
end | end | ||
end | end | ||
Line 2,442: | Line 2,565: | ||
if 'episode' == config.CitationClass or 'serial' == config.CitationClass then | if 'episode' == config.CitationClass or 'serial' == config.CitationClass then | ||
local AirDate = A['AirDate']; | local AirDate = A['AirDate']; | ||
local SeriesLink = A['SeriesLink']; | local SeriesLink = A['SeriesLink']; | ||
local Network = A['Network']; | local Network = A['Network']; | ||
Line 2,457: | Line 2,578: | ||
if is_set (AirDate) then | if is_set (AirDate) then | ||
Date = AirDate; | Date = AirDate; | ||
end | end | ||
end | end | ||
Line 2,481: | Line 2,596: | ||
Chapter = Title; -- promote title parameters to chapter | Chapter = Title; -- promote title parameters to chapter | ||
ScriptChapter = ScriptTitle; | |||
ChapterLink = TitleLink; -- alias episodelink | ChapterLink = TitleLink; -- alias episodelink | ||
TransChapter = TransTitle; | TransChapter = TransTitle; | ||
Line 2,496: | Line 2,612: | ||
end | end | ||
URL = ''; -- unset | URL = ''; -- unset | ||
TransTitle = ''; | TransTitle = ''; | ||
ScriptTitle = ''; | |||
else -- now oddities that are cite serial | else -- now oddities that are cite serial | ||
Issue = ''; | Issue = ''; -- unset because this parameter no longer supported by the citation/core version of cite serial | ||
Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? | Chapter = A['Episode']; -- TODO: make |episode= available to cite episode someday? | ||
if is_set (Series) and is_set (SeriesLink) then | if is_set (Series) and is_set (SeriesLink) then | ||
Line 2,550: | Line 2,667: | ||
-- legacy: promote concatenation of |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set. | -- legacy: promote concatenation of |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set. | ||
if not is_set (Date) then | if not is_set (Date) then | ||
Date = Year; | Date = Year; -- promote Year to Date | ||
Year = nil; | Year = nil; -- make nil so Year as empty string isn't used for CITEREF | ||
if is_set(Date) | if not is_set (Date) and is_set(PublicationDate) then -- use PublicationDate when |date= and |year= are not set | ||
Date = PublicationDate; -- promote PublicationDate to Date | |||
PublicationDate = ''; -- unset, no longer needed | |||
Date = PublicationDate; | |||
PublicationDate = ''; | |||
end | end | ||
end | end | ||
Line 2,574: | Line 2,686: | ||
local error_message = ''; | local error_message = ''; | ||
-- AirDate has been promoted to Date so not necessary to check it | -- AirDate has been promoted to Date so not necessary to check it | ||
anchor_year, COinS_date, error_message = dates({[' | anchor_year, COinS_date, error_message = dates({['access-date']=AccessDate, ['archive-date']=ArchiveDate, ['date']=Date, ['doi-broken-date']=DoiBroken, | ||
['embargo']=Embargo, [' | ['embargo']=Embargo, ['lay-date']=LayDate, ['publication-date']=PublicationDate, ['year']=Year}); | ||
if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed; | if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed; | ||
Line 2,610: | Line 2,722: | ||
not is_set(TransTitle) and | not is_set(TransTitle) and | ||
not is_set(ScriptTitle) then | not is_set(ScriptTitle) then | ||
if 'episode' == config.CitationClass then -- special case for cite episode; is there a better way to do this? | |||
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'series'}, true ) } ); | |||
else | |||
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'title'}, true ) } ); | |||
end | |||
end | end | ||
Line 2,617: | Line 2,733: | ||
add_maint_cat ('untitled'); | add_maint_cat ('untitled'); | ||
end | end | ||
check_for_url ({['title']=Title, ['chapter']=Chapter, ['work']=Periodical}); -- adds error message when any of these parameters contain a URL | |||
-- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. | -- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information. | ||
Line 2,635: | Line 2,753: | ||
local OCinSoutput = COinS({ | local OCinSoutput = COinS({ | ||
['Periodical'] = Periodical, | ['Periodical'] = Periodical, | ||
['Chapter'] = | ['Chapter'] = make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic wikimarkup | ||
['Title'] = make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic wikimarkup | ['Title'] = make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic wikimarkup | ||
['PublicationPlace'] = PublicationPlace, | ['PublicationPlace'] = PublicationPlace, | ||
Line 2,668: | Line 2,786: | ||
-- We also add leading spaces and surrounding markup and punctuation to the | -- We also add leading spaces and surrounding markup and punctuation to the | ||
-- various parts of the citation, but only when they are non-nil. | -- various parts of the citation, but only when they are non-nil. | ||
local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list | |||
do | |||
local last_first_list; | |||
local maximum; | |||
local control = { | |||
format = NameListFormat, -- empty string or 'vanc' | |||
maximum = nil, -- as if display-authors or display-editors not set | |||
lastauthoramp = LastAuthorAmp, | |||
page_name = this_page.text -- get current page name so that we don't wikilink to it via editorlinkn | |||
}; | |||
do -- do editor name list first because coauthors can modify control table | |||
maximum , editor_etal = get_display_authors_editors (A['DisplayEditors'], #e, 'editors', editor_etal); | |||
-- Preserve old-style implicit et al. | |||
if not is_set(maximum) and #e == 4 then | |||
maximum = 3; | |||
table.insert( z.message_tail, { set_error('implict_etal_editor', {}, true) } ); | |||
end | |||
control.maximum = maximum; | |||
last_first_list, EditorCount = list_people(control, e, editor_etal); | |||
if is_set (Editors) then | |||
if editor_etal then | |||
Editors = Editors .. ' ' .. cfg.messages['et al']; -- add et al. to editors parameter beause |display-editors=etal | |||
EditorCount = 2; -- with et al., |editors= is multiple names; spoof to display (eds.) annotation | |||
else | |||
EditorCount = 2; -- we don't know but assume |editors= is multiple names; spoof to display (eds.) annotation | |||
end | |||
else | |||
Editors = last_first_list; -- either an author name list or an empty string | |||
end | |||
if 1 == EditorCount and (true == editor_etal or 1 < #e) then -- only one editor displayed but includes etal then | |||
EditorCount = 2; -- spoof to display (eds.) annotation | |||
end | |||
end | |||
do -- now do translators | |||
control.maximum = #t; -- number of translators | |||
Translators = list_people(control, t, false); -- et al not currently supported | |||
end | |||
do -- now do authors | |||
control.maximum , author_etal = get_display_authors_editors (A['DisplayAuthors'], #a, 'authors', author_etal); | |||
if is_set(Coauthors) then -- if the coauthor field is also used, prevent ampersand and et al. formatting. | |||
control.lastauthoramp = nil; | |||
control.maximum = #a + 1; | |||
end | |||
last_first_list = list_people(control, a, author_etal); | |||
if is_set (Authors) then | |||
Authors, author_etal = name_has_etal (Authors, author_etal, false); -- find and remove variations on et al. | |||
if author_etal then | |||
Authors = Authors .. ' ' .. cfg.messages['et al']; -- add et al. to authors parameter | |||
end | |||
else | |||
Authors = last_first_list; -- either an author name list or an empty string | |||
end | |||
end -- end of do | |||
if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified | |||
table.insert( z.message_tail, { set_error('coauthors_missing_author', {}, true) } ); -- emit error message | |||
end | |||
end | |||
--[[ | |||
do -- do-block to limit scope of last_first_list | do -- do-block to limit scope of last_first_list | ||
local last_first_list; | local last_first_list; | ||
Line 2,739: | Line 2,928: | ||
end | end | ||
end | end | ||
]] | |||
-- apply |[xx-]format= styling; at the end, these parameters hold correctly styled format annotation, | -- apply |[xx-]format= styling; at the end, these parameters hold correctly styled format annotation, | ||
Line 2,791: | Line 2,980: | ||
if in_array(config.CitationClass, {"web","news","journal","pressrelease","podcast", "newsgroup", 'arxiv'}) or | if in_array(config.CitationClass, {"web","news","journal","pressrelease","podcast", "newsgroup", 'arxiv'}) or | ||
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) then | ('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) then | ||
if is_set (Chapter) or is_set (TransChapter) or is_set (ChapterURL)then -- chapter parameters not supported for these citation types | if is_set (Chapter) or is_set (TransChapter) or is_set (ChapterURL) or is_set (ScriptChapter) then -- chapter parameters not supported for these citation types | ||
table.insert( z.message_tail, { set_error( 'chapter_ignored', {}, true ) } ); -- add error message | table.insert( z.message_tail, { set_error( 'chapter_ignored', {A:ORIGIN ('Chapter')}, true ) } ); -- add error message | ||
Chapter = ''; | Chapter = ''; -- set them to empty string to be safe with concatenation | ||
TransChapter = ''; | TransChapter = ''; | ||
ChapterURL = ''; | ChapterURL = ''; | ||
ScriptChapter = ''; | |||
end | end | ||
else -- otherwise, format chapter / article title | else -- otherwise, format chapter / article title | ||
Chapter = format_chapter_title (Chapter, TransChapter, ChapterURL, ChapterURLorigin); | Chapter = format_chapter_title (ScriptChapter, Chapter, TransChapter, ChapterURL, ChapterURLorigin); | ||
if is_set (Chapter) then | if is_set (Chapter) then | ||
if 'map' == config.CitationClass and is_set (TitleType) then | if 'map' == config.CitationClass and is_set (TitleType) then | ||
Line 2,834: | Line 3,024: | ||
TransTitle = " " .. TransTitle; | TransTitle = " " .. TransTitle; | ||
else | else | ||
TransError = " " .. set_error( 'trans_missing_title' ); | TransError = " " .. set_error( 'trans_missing_title', {'title'} ); | ||
end | end | ||
end | end | ||
Line 2,963: | Line 3,153: | ||
Others = is_set(Others) and (sepc .. " " .. Others) or ""; | Others = is_set(Others) and (sepc .. " " .. Others) or ""; | ||
if is_set (Translators) then | |||
Others = sepc .. ' Translated by ' .. Translators .. Others; | |||
end | |||
TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or ""; | TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or ""; | ||
if is_set (Edition) then | if is_set (Edition) then | ||
if Edition:match ('[Ee]d%.?$') or Edition:match ('[Ee]dition$') then | if Edition:match ('%f[%a][Ee]d%.?$') or Edition:match ('%f[%a][Ee]dition$') then | ||
add_maint_cat ('extra_text', 'edition'); | add_maint_cat ('extra_text', 'edition'); | ||
end | end | ||
Line 2,995: | Line 3,189: | ||
]] | ]] | ||
if | if is_set (SubscriptionRequired) then | ||
SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message | SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message | ||
elseif | elseif is_set (RegistrationRequired) then | ||
SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; -- registration required message | SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; -- registration required message | ||
else | else | ||
Line 3,048: | Line 3,242: | ||
Archived = Archived .. " " .. set_error('archive_missing_url'); | Archived = Archived .. " " .. set_error('archive_missing_url'); | ||
end | end | ||
elseif is_set(OriginalURL) then | elseif is_set(OriginalURL) then -- DeadURL is empty, 'yes', 'true', 'y', 'unfit', 'usurped' | ||
local arch_text = cfg.messages['archived-dead']; | local arch_text = cfg.messages['archived-dead']; | ||
if sepc ~= "." then arch_text = arch_text:lower() end | if sepc ~= "." then arch_text = arch_text:lower() end | ||
Archived = sepc .. " " .. substitute( arch_text, | -- if 'usurped' == DeadURL then -- when original has unsuitable content do not link | ||
if in_array (DeadURL, {'unfit', 'usurped'}) then | |||
Archived = sepc .. " " .. 'Archived from the original on ' .. ArchiveDate; -- format already styled | |||
else -- DeadURL is empty, 'yes', 'true', or 'y' | |||
Archived = sepc .. " " .. substitute( arch_text, | |||
{ external_link( OriginalURL, cfg.messages['original'] ) .. OriginalFormat, ArchiveDate } ); -- format already styled | |||
end | |||
else | else | ||
local arch_text = cfg.messages['archived-missing']; | local arch_text = cfg.messages['archived-missing']; | ||
Line 3,267: | Line 3,466: | ||
text = safe_join( {text, PostScript}, sepc ); | text = safe_join( {text, PostScript}, sepc ); | ||
-- Now enclose the whole thing in a < | -- Now enclose the whole thing in a <cite/> element | ||
local options = {}; | local options = {}; | ||
if is_set(config.CitationClass) and config.CitationClass ~= "citation" then | if is_set(config.CitationClass) and config.CitationClass ~= "citation" then | ||
options.class = "citation " .. config.CitationClass; | options.class = config.CitationClass; | ||
options.class = "citation " .. config.CitationClass; -- class=citation required for blue highlight when used with |ref= | |||
else | else | ||
options.class = "citation"; | options.class = "citation"; | ||
Line 3,304: | Line 3,504: | ||
if is_set(options.id) then | if is_set(options.id) then | ||
text = '< | text = '<cite id="' .. mw.uri.anchorEncode(options.id) ..'" class="' .. mw.text.nowiki(options.class) .. '">' .. text .. "</cite>"; | ||
else | else | ||
text = '< | text = '<cite class="' .. mw.text.nowiki(options.class) .. '">' .. text .. "</cite>"; | ||
end | end | ||
Line 3,381: | Line 3,581: | ||
end | end | ||
local capture; -- the single supported capture when matching unknown parameters using patterns | |||
for k, v in pairs( pframe.args ) do | for k, v in pairs( pframe.args ) do | ||
if v ~= '' then | if v ~= '' then | ||
Line 3,393: | Line 3,594: | ||
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true ); | error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true ); | ||
else | else | ||
if #suggestions = | if nil == suggestions.suggestions then -- if this table is nil then we need to load it | ||
suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions' ); | if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version? | ||
suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions/sandbox' ); -- use the sandbox version | |||
else | |||
suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions' ); -- use the live version | |||
end | |||
end | |||
for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter | |||
capture = k:match (pattern); -- the whole match if no caputre in pattern else the capture if a match | |||
if capture then -- if the pattern matches | |||
param = substitute( param, capture ); -- add the capture to the suggested parameter (typically the enumerator) | |||
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, param}, true ); -- set the error message | |||
end | |||
end | end | ||
if suggestions[ k:lower() ] ~= nil then | if not is_set (error_text) then -- couldn't match with a pattern, is there an expicit suggestion? | ||
if suggestions.suggestions[ k:lower() ] ~= nil then | |||
error_text, error_state = set_error( 'parameter_ignored_suggest', {k, suggestions.suggestions[ k:lower() ]}, true ); | |||
else | |||
error_text, error_state = set_error( 'parameter_ignored', {k}, true ); | |||
end | |||
end | end | ||
-- if #suggestions == 0 then | |||
-- suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions' ); | |||
-- end | |||
-- if suggestions[ k:lower() ] ~= nil then | |||
-- error_text, error_state = set_error( 'parameter_ignored_suggest', {k, suggestions[ k:lower() ]}, true ); | |||
-- else | |||
-- error_text, error_state = set_error( 'parameter_ignored', {k}, true ); | |||
-- end | |||
end | end | ||
if error_text ~= '' then | if error_text ~= '' then |