Module:Citation/CS1: திருத்தங்களுக்கு இடையிலான வேறுபாடு

உள்ளடக்கம் நீக்கப்பட்டது உள்ளடக்கம் சேர்க்கப்பட்டது
bug fix in page number rendering (NoPP);
Synch from sandbox;
வரிசை 27:
--[[--------------------------< F I R S T _ S E T >------------------------------------------------------------
 
Locates and returns the first set value in a table of values where the order established in the table,
First set variable or nil if none
left-to-right (or top-to-bottom), is the order in which the values are evaluated. Returns nil if none are set.
 
This version replaces the original 'for _, val in pairs do' and a similar version that used ipairs. With the pairs
version the order of evaluation could not be guaranteed. With the ipairs version, a nil value would terminate
the for-loop before it reached the actual end of the list.
 
]]
 
local function first_set (...list, count)
local listi = {...}1;
while i <= count do -- loop through all items in list
for _, var in pairs(list) do
if is_set( varlist[i] ) then
return list[i]; -- return the first set list member
return var;
end
i = i + 1; -- point to next
end
end
வரி 160 ⟶ 166:
end
 
--[[--------------------------< C H E C K _ U R L >------------------------------------------------------------
 
--[[--------------------------< I S _ S C H E M E >------------------------------------------------------------
Determines whether a URL string is valid.
 
Atdoes presentthis thething onlythat checkpurports isto whetherbe thea stringuri appearsscheme seem to be prefixed with a URIvalid scheme.? ItThe scheme is notchecked to determinedsee whetherif it
is in agreement with http://tools.ietf.org/html/std66#section-3.1 which says:
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 ("-").
 
returns true if it does, else false
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 is_scheme (scheme)
return scheme and scheme:match ('^%a[%a%d%+%.%-]*:'); -- true if scheme is set and matches the pattern
end
 
 
--[[--------------------------< I S _ D O M A I N _ N A M E >--------------------------------------------------
 
Does this thing that purports to be a domain name seem to be a valid domain name?
 
rfc952 (modified by rfc 1123) requires the first and last character of a hostname to be a letter or a digit. Between
the first and last characters the name may use letters, digits, and the hyphen. Single character names are not allowed.
 
Also allowed are IPv4 addresses. IPv6 not supported
 
There are three tests: the first is looking for a hostname that is 2 to n letters or digits followed by a dot and a
letter (tld); the second looks for a hostname that is 3 to n characters where the first and last are letters or
digits and the middle characters are letters, digits, or the hyphen; the whole followed by a dot and a letter or digit.
The third test is for IPv4 dot-decimal address format; tld not allowed.
 
returns true if domain appears to be a proper name and tld or IPv4 address, else false
 
]]
 
local function is_domain_name (domain)
if not domain then
return false; -- if not set, abandon
end
domain = domain:gsub ('^//', ''); -- strip '//' from domain name if present; done here so we only have to do it once
if domain:match ('^[%a%d][%a%d]+%.%a') then -- two character hostname and tld
return true;
elseif domain:match ('^[%a%d][%a%d%-]+[%a%d]%.[%a%d]') then -- three or more character hostname.hostname or hostname.tld
return true;
elseif domain:match ('^%d%d?%d?%.%d%d?%d?%.%d%d?%d?%.%d%d?%d?') then -- IPv4 address
return true;
else
return false;
end
end
 
 
--[[--------------------------< I S _ U R L >------------------------------------------------------------------
 
returns true if the scheme and domain parts of a url appear to be a valid url; else false.
 
This function is the last step in the validation process. This function is separate because there are cases that
are not covered by split_url(), for example is_parameter_ext_wikilink() which is looking for bracketted external
wikilinks.
 
]]
 
local function is_url (scheme, domain)
if is_set (scheme) then -- if scheme is set check it and domain
return is_scheme (scheme) and is_domain_name (domain);
else
return is_domain_name (domain); -- scheme not set when url is protocol relative
end
end
 
 
--[[--------------------------< S P L I T _ U R L >------------------------------------------------------------
 
Split a url into a scheme and domain pair and return both parts. If protocol relative url, return nil for scheme
and domain else return nil for both scheme and domain.
 
]]
 
local function split_url (url_str)
local scheme, domain;
if url_str:match ('%S-:%S+') then -- if there is what appears to be a scheme domain pair
scheme, domain = url_str:match ('(%S-:)(%S+)'); -- extract the scheme and domain portions
elseif url_str:match ('//%S*') then -- if there is what appears to be a protocol relative url
domain = url_str:match ('//(%S*)')
end
return scheme, domain;
end
 
 
--[[--------------------------< L I N K _ P A R A M _ O K >---------------------------------------------------
 
checks the content of |title-link=, |series-link=, |author-link= etc for properly formatted content: no wikilinks, no urls
 
Link parameters are to hold the title of a wikipedia article so none of the WP:TITLESPECIALCHARACTERS are allowed:
# < > [ ] | { } _
returns false when the value contains any of these characters.
 
When there are no illegal characters, this function returns TRUE if value DOES NOT appear to be a valid url (the
|<param>-link= parameter is ok); else false when value appears to be a valid url (the |<param>-link= parameter is NOT ok).
 
]]
 
local function link_param_ok (value)
local scheme, domain;
if value:find ('[#<>%[%]|{}_]') then -- if any prohibited characters
return false;
end
 
scheme, domain = split_url (value); -- get scheme or nil and domain or nil from url;
return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid url
end
 
 
--[[--------------------------< C H E C K _ U R L >------------------------------------------------------------
 
Determines whether a URL string appears to be valid.
 
First we test for space characters. If any are found, return false. Then split the url into scheme and domain
portions, or for protocol relative (//example.com) urls, just the domain. Use is_scheme() and is_domain() to
validate the two portions of the url. If both are valid, or for protocol relative if domain is valid, return true, else false.
 
]]
 
local function check_url( url_str )
if nil == url_str:match ("^%S+$") then -- if there are any spaces in |url=value it can't be a proper url
return false;
end
local scheme, domain;
return url_str:sub(1,2) == "//" or nil ~= url_str:match ("^%a[%a%d%+%.%-]*:") -- protocol relative or scheme part composed of legitimate characters
 
scheme, domain = split_url (url_str); -- get scheme or nil and domain or nil from url;
return is_url (scheme, domain); -- return true if value appears to be a valid url
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. Also finds bare urls.
 
The frontier pattern prevents a match on interwiki links which are similar to scheme:path urls. The tests that
find bracketed urls are required because the parameters that call this test (currently |title=, |chapter=, and
|work=) may have wikilinks and there are articles or redirects like '//Hus' so, while uncommon, |title=[[//Hus]] is
possible as might be [[en://Hus]].
 
]=]
 
local function is_parameter_ext_wikilink (value)
local scheme, domain;
 
if value:match ('%f[%[]%[%a%S*:%S.*%]') then -- if ext wikilink with scheme and domain: [xxxx://yyyyy.zzz]
scheme, domain = value:match ('%f[%[]%[(%a%S*:)(%S.*)%]')
elseif value:match ('%f[%[]%[//%S*%.%S*%]') then -- if protocol relative ext wikilink: [//yyyyy.zzz]
domain = value:match ('%f[%[]%[//(%S*%.%S*)%]');
else
scheme, domain = split_url (value); -- get scheme or nil and domain or nil from url;
end
 
return is_url (scheme, domain); -- return true if value appears to be a valid url
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 .. "&#124;" .. 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
 
 
--[[--------------------------< S A F E _ F O R _ I T A L I C S >----------------------------------------------
வரி 259 ⟶ 429:
end
if not check_url( URL ) then
error_str = set_error( 'bad_url', {wrap_style ('parameter', source)}, false, " " ) .. error_str;
end
return table.concat({ "[", URL, " ", safe_for_url( label ), "]", error_str });
வரி 411 ⟶ 581:
local msg;
msg = cfg.messages[key]:lower(); -- set the message to lower case before
str =return substitute( msg, {str} ); -- including template text
return str;
else
return substitute( cfg.messages[key], {str} );
end
end
 
 
--[[-------------------------< I S _ A L I A S _ U S E D >-----------------------------------------------------
 
This function is used by select_one() to determine if one of a list of alias parameters is in the argument list
provided by the template.
 
Input:
args – pointer to the arguments table from calling template
alias – one of the list of possible aliases in the aliases lists from Module:Citation/CS1/Configuration
index – for enumerated parameters, identifies which one
enumerated – true/false flag used choose how enumerated aliases are examined
value – value associated with an alias that has previously been selected; nil if not yet selected
selected – the alias that has previously been selected; nil if not yet selected
error_list – list of aliases that are duplicates of the alias already selected
 
Returns:
value – value associated with alias we selected or that was previously selected or nil if an alias not yet selected
selected – the alias we selected or the alias that was previously selected or nil if an alias not yet selected
 
]]
 
local function is_alias_used (args, alias, index, enumerated, value, selected, error_list)
if enumerated then -- is this a test for an enumerated parameters?
alias = alias:gsub ('#', index); -- replace '#' with the value in index
else
alias = alias:gsub ('#', ''); -- remove '#' if it exists
end
 
if is_set(args[alias]) then -- alias is in the template's argument list
if value ~= nil and selected ~= alias then -- if we have already selected one of the aliases
local skip;
for _, v in ipairs(error_list) do -- spin through the error list to see if we've added this alias
if v == alias then
skip = true;
break; -- has been added so stop looking
end
end
if not skip then -- has not been added so
table.insert( error_list, alias ); -- add error alias to the error list
end
else
value = args[alias]; -- not yet selected an alias, so select this one
selected = alias;
end
end
return value, selected; -- return newly selected alias, or previously selected alias
end
 
 
--[[--------------------------< S E L E C T _ O N E >----------------------------------------------------------
 
Chooses one matching parameter from a list of parameters to consider. The list of parameters to consider is just
names. For parameters that may be enumerated, the position of the numerator in the parameter name is identified
by the '#' so |author-last1= and |author1-last= are represented as 'author-last#' and 'author#-last'.
 
Because enumerated parameter |<param>1= is an alias of |<param>= we must test for both possibilities.
 
 
Generates an error if more than one match is present.
 
]]
 
local function select_one( args, possiblealiases_list, error_condition, index )
local value = nil; -- the value assigned to the selected parameter
local selected = ''; -- the name of the parameter we have chosen
local error_list = {};
 
if index ~= nil then index = tostring(index); end
 
for _, alias in ipairs( aliases_list ) do -- for each alias in the aliases list
-- Handle special case of "#" replaced by empty string
if alias:match ('#') then -- if this alias can be enumerated
if index == '1' then
if '1' == index then -- when index is 1 test for enumerated and non-enumerated aliases
for _, v in ipairs( possible ) do
value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); -- first test for non-enumerated alias
v = v:gsub( "#", "" );
if is_set(args[v]) 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 is_set(args[v]) then
if value ~= nil and selected ~= v then
table.insert( error_list, v );
else
value = args[v];
selected = v;
end
value, selected = is_alias_used (args, alias, index, true, value, selected, error_list); -- test for enumerated alias
else
value, selected = is_alias_used (args, alias, index, false, value, selected, error_list); --test for non-enumerated alias
end
end
 
if #error_list > 0 and 'none' ~= error_condition then -- for cases where this code is used outside of extract_names()
if #error_list > 0 then
local error_str = "";
for _, k in ipairs( error_list ) do
வரி 478 ⟶ 684:
return value, selected;
end
 
 
--[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------------------------------
வரி 486 ⟶ 693:
]]
 
local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes)
local chapter_error = '';
வரி 492 ⟶ 699:
chapter = ''; -- to be safe for concatenation
else
if false == no_quotes then
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
end
 
வரி 623 ⟶ 832:
date = substitute (cfg.presentation['nowrap1'], date);
elseif date:match("^%a+%s*%d%d?,%s*+%d%d%d%d$") or date:match ("^%d%d?%s*%a+%s*+%d%d%d%d$") then
cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$");
date = substitute (cfg.presentation['nowrap2'], {cap, cap2});
வரி 1,101 ⟶ 1,310:
end
 
 
-- Formats an OpenLibrary link, and checks for associated errors.
--[[--------------------------< O P E N L I B R A R Y >--------------------------------------------------------
 
Formats an OpenLibrary link, and checks for associated errors.
 
]]
local function openlibrary(id)
local code = id:match("^%d+([AMW])$"); -- only digits followed by 'A', 'M', or 'W'
local handler = cfg.id_handlers['OL'];
 
வரி 1,414 ⟶ 1,628:
]]
 
local function list_people(control, people, etal, list_name) -- TODO: why is list_name here? not used in this function
local sep;
local namesep;
வரி 1,464 ⟶ 1,678:
one = "[[" .. person.link .. "|" .. one .. "]]" -- link author/editor if this page is not the author's/editor's page
end
 
if is_set(person.link) and ((nil ~= person.link:find("//")) or (nil ~= person.link:find("[%[%]]"))) then
one = one .. " " .. set_error( 'bad_authorlink' ) end -- url or wikilink in author link;
end
table.insert( text, one )
வரி 1,483 ⟶ 1,694:
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
result = result .. sep .. ' ' .. cfg.messages['et al']; -- we've go a last-first list and etal so add et al.
end
வரி 1,493 ⟶ 1,704:
Generates a CITEREF anchor ID if we have at least one name or a date. Otherwise returns an empty string.
 
namelist is one of the contributor-, author-, or editor-name lists chosen in that order. year is Year or anchor_year.
]]
 
]]
local function anchor_id( options )
local function anchor_id (namelist, year)
local id = table.concat( options ); -- concatenate names and year for CITEREF id
local names={}; -- a table for the one to four names and year
for i,v in ipairs (namelist) do -- loop through the list and take up to the first four last names
names[i] = v.last
if i == 4 then break end -- if four then done
end
table.insert (names, year); -- add the year at the end
local id = table.concat(names); -- concatenate names and year for CITEREF id
if is_set (id) then -- if concatenation is not an empty string
return "CITEREF" .. id; -- add the CITEREF portion
வரி 1,503 ⟶ 1,721:
end
end
 
 
--[[--------------------------< N A M E _ H A S _ E T A L >----------------------------------------------------
வரி 1,517 ⟶ 1,736:
 
if is_set (name) then -- name can be nil in which case just return
local etal_pattern = "[;,]? *[\"']*%f[Ee%a][Ee][Tt] *[Aa][Ll][%.\"']*$" -- variations on the 'et al' theme
local others_pattern = "[;,]? *%f[%a]and [Oo]thers"; -- and alternate to et al.
வரி 1,582 ⟶ 1,801:
end
else -- we have last with or without a first
if is_set (link) and false == link_param_ok (link) then -- do this test here in case link is missing last
table.insert( z.message_tail, { set_error( 'bad_paramlink', list_name:match ("(%w+)List"):lower() .. '-link' .. i )}); -- url or wikilink in author link;
end
names[n] = {last = last, first = first, link = link, mask = mask, corporate=false}; -- add this name to our names list (corporate for |vauthors= only)
n = n + 1; -- point to next location in the names table
வரி 1,595 ⟶ 1,817:
end
 
--[[--------------------------< B U I L D _ I D _ L I S T >--------------------------------------------------------
-- Populates ID table from arguments using configuration settings
 
Populates ID table from arguments using configuration settings. Loops through cfg.id_handlers and searches args for
any of the parameters listed in each cfg.id_handlers['...'].parameters. If found, adds the parameter and value to
the identifier list. Emits redundant error message is more than one alias exists in args
 
]]
 
local function extract_ids( args )
local id_list = {}; -- list of identifiers found in args
for k, v in pairs( cfg.id_handlers ) do -- k is uc identifier name as index to cfg.id_handlers; e.g. cfg.id_handlers['ISBN'], v is a table
v = select_one( args, v.parameters, 'redundant_parameters' ); -- v.parameters is a table of aliases for k; here we pick one from args if present
if is_set(v) then id_list[k] = v; end -- if found in args, add identifier to our list
end
return id_list;
வரி 1,607 ⟶ 1,836:
--[[--------------------------< B U I L D _ I D _ L I S T >--------------------------------------------------------
 
Takes a table of IDs created by extract_ids() and turns it into a table of formatted ID outputs.
 
inputs:
id_list – table of identifiers built by extract_ids()
options – table of various template parameter values used to modify some manually handled identifiers
 
]]
வரி 1,616 ⟶ 1,849:
function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end;
for k, v in pairs( id_list ) do -- k is uc identifier name as index to cfg.id_handlers; e.g. cfg.id_handlers['ISBN'], v is a table
-- fallback to read-only cfg
handler = setmetatable( { ['id'] = v }, fallback(k) );
வரி 1,634 ⟶ 1,867:
elseif k == 'LCCN' then
table.insert( new_list, {handler.label, lccn( v ) } );
elseif k == 'OL' or k == 'OLA' then
table.insert( new_list, {handler.label, openlibrary( v ) } );
elseif k == 'PMC' then
வரி 1,692 ⟶ 1,925:
});
if in_array (class, {'citationarxiv', 'journal', 'news'}) or (in_array (class, {'conference', 'interview', 'map', 'press release', 'web'}) and is_set(data.Periodical)) or then
('citation' == class and is_set(data.Periodical) and not is_set (data.Encyclopedia)) then
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";
OCinSoutput["rft.genre"]rft_val_fmt = "articleinfo:ofi/fmt:kev:mtx:journal"; -- journal metadata identifier
if 'arxiv' == class then -- set genre according to the type of citation template we are rendering
OCinSoutput["rft.jtitle"] = data.Periodical;
OCinSoutput["rft.atitlegenre"] = data.Title"preprint"; -- cite arxiv
elseif in_array (class, {'arxivconference', 'journal',== 'news'})class then
OCinSoutput["rft.genre"] = "conference"; -- cite conference (when Periodical set)
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";
if elseif 'arxivweb' == class then
OCinSoutput["rft.genre"] = "preprintunknown"; -- cite arxivweb (when Periodical set)
else
OCinSoutput["rft.genre"] = "article"; -- journal and other 'periodical' articles
end
OCinSoutput["rft.jtitle"] = data.Periodical; -- journal only
if is_set (data.Map) then
OCinSoutput["rft.atitle"] = data.Map; -- for a map in a periodical
else
OCinSoutput["rft.atitle"] = data.Title; -- all other 'periodical' article titles
end
-- these used onlu for periodicals
OCinSoutput["rft.ssn"] = data.Season; -- keywords: winter, spring, summer, fall
OCinSoutput["rft.chron"] = data.Chron; -- free-form date components
OCinSoutput["rft.volume"] = data.Volume; -- does not apply to books
OCinSoutput["rft.issue"] = data.Issue;
OCinSoutput["rft.pages"] = data.Pages; -- also used in book metadata
 
elseif 'thesis' ~= class then -- all others except cite thesis are treated as 'book' metadata; genre distinguishes
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book"; -- book metadata identifier
if 'report' == class or 'techreport' == class then -- cite report and cite techreport
OCinSoutput["rft.genre"] = "report";
elseif 'conference' == class then -- cite conference when Periodical not set
OCinSoutput["rft.genre"] = "conference";
elseif in_array (class, {'book', 'citation', 'encyclopaedia', 'interview', 'map'}) then
if is_set (data.Chapter) then
OCinSoutput["rft.genre"] = "bookitem";
OCinSoutput["rft.atitle"] = data.Chapter; -- book chapter, encyclopedia article, interview in a book, or map title
else
if 'map' == class or 'interview' == class then
OCinSoutput["rft.genre"] = 'unknown'; -- standalone map or interview
else
OCinSoutput["rft.genre"] = 'book'; -- book and encyclopedia
end
end
else --{'audio-visual', 'AV-media-notes', 'DVD-notes', 'episode', 'interview', 'mailinglist', 'map', 'newsgroup', 'podcast', 'press release', 'serial', 'sign', 'speech', 'web'}
OCinSoutput["rft.genre"] = "unknown";
end
OCinSoutput["rft.jtitlebtitle"] = data.PeriodicalTitle; -- book only
OCinSoutput["rft.atitleplace"] = data.TitlePublicationPlace; -- book only
OCinSoutput["rft.series"] = data.Series; -- book only
else
OCinSoutput["rft.rft_val_fmtpages"] = "info:ofi/fmt:kev:mtx:book"data.Pages; -- book, journal
OCinSoutput["rft.edition"] = data.Edition; -- book only
if is_set (data.Chapter) then
OCinSoutput["rft.genrepub"] = "bookitem"data.PublisherName; -- book and dissertation
OCinSoutput["rft.atitle"] = data.Chapter;
else -- cite thesis
else
OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:dissertation"; -- dissertation metadata identifier
OCinSoutput["rft.genre"] = "book"
OCinSoutput["rft.title"] = data.Title; -- dissertation (also patent but that is not yet supported)
OCinSoutput["rft.degree"] = data.Degree; -- dissertation only
OCinSoutput['rft.inst'] = data.PublisherName; -- book and dissertation
end
-- and now common parameters (as much as possible)
OCinSoutput["rft.date"] = data.Date; -- book, journal, dissertation
for k, v in pairs( data.ID_list ) do -- what to do about these? For now assume that they are common to all?
if k == 'ISBN' then v = clean_isbn( v ) end
local id = cfg.id_handlers[k].COinS;
if string.sub( id or "", 1, 4 ) == 'info' then -- for ids that are in the info:registry
OCinSoutput["rft_id"] = table.concat{ id, "/", v };
elseif string.sub (id or "", 1, 3 ) == 'rft' then -- for isbn, issn, eissn, etc that have defined COinS keywords
OCinSoutput[ id ] = v;
elseif id then -- when cfg.id_handlers[k].COinS is not nil
OCinSoutput["rft_id"] = table.concat{ cfg.id_handlers[k].prefix, v }; -- others; provide a url
end
OCinSoutput["rft.btitle"] = data.Title;
end
 
--[[
OCinSoutput["rft.place"] = data.PublicationPlace;
for k, v in pairs( data.ID_list ) do -- what to do about these? For now assume that they are common to all?
OCinSoutput["rft.date"] = data.Date;
OCinSoutput["rft.series"] = data.Series;
OCinSoutput["rft.volume"] = data.Volume;
OCinSoutput["rft.issue"] = data.Issue;
OCinSoutput["rft.pages"] = data.Pages;
OCinSoutput["rft.edition"] = data.Edition;
OCinSoutput["rft.pub"] = data.PublisherName;
for k, v in pairs( data.ID_list ) do
local id, value = cfg.id_handlers[k].COinS;
if k == 'ISBN' then value = clean_isbn( v ); else value = v; end
வரி 1,735 ⟶ 2,008:
end
end
]]
local last, first;
for k, v in ipairs( data.Authors ) do
வரி 1,741 ⟶ 2,014:
if k == 1 then -- for the first author name only
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; -- book, journal, dissertation
OCinSoutput["rft.aufirst"] = first; -- book, journal, dissertation
elseif is_set(last) then
OCinSoutput["rft.au"] = last; -- book, journal, dissertation -- otherwise use this form for the first name
end
else -- for all other authors
if is_set(last) and is_set(first) then
OCinSoutput["rft.au"] = table.concat{ last, ", ", first }; -- book, journal, dissertation
elseif is_set(last) then
OCinSoutput["rft.au"] = last; -- book, journal, dissertation
end
end
வரி 1,834 ⟶ 2,107:
for _, lang in ipairs (names_table) do -- reuse lang
 
if lang:match ('^%a%a%-') then -- strip ietf language tags from code
lang = lang:match ('(%a%a)%-') -- keep only 639-1 code portion to lang; TODO: do something with 3166 alpha 2 country code?
end
if 2 == lang:len() then -- ISO639-1 language code are 2 characters (fetchLanguageName also supports 3 character codes)
name = mw.language.fetchLanguageName( lang:lower(), "en" ); -- get ISO 639-1 language name if Language is a proper code
வரி 1,865 ⟶ 2,141:
end
if 'English' == name then
return ''; -- if one language and that language is English return an enptyempty string (no annotation)
end
return (" " .. wrap_msg ('language', name)); -- otherwise wrap with '(in ...)'
வரி 2,024 ⟶ 2,300:
]]
 
local function extra_text_in_page_check (page, nopp)
-- local good_pattern = '^P[^%.P%l]';
local good_pattern = '^P[^%.Pp]'; -- ok to begin with uppercase P: P7 (pg 7 of section P) but not p123 (page 123) TODO: add Gg for PG or Pg?
-- local bad_pattern = '^[Pp][Pp]';
local bad_pattern = '^[Pp]?[Pp]%.?[ %d]';
 
if is_set (nopp) then -- don't bother checking if |nopp= is set
return;
end
 
if not page:match (good_pattern) and (page:match (bad_pattern) or page:match ('^[Pp]ages?')) then
வரி 2,119 ⟶ 2,391:
local function select_author_editor_source (vxxxxors, xxxxors, args, list_name)
local lastfirst = false;
if select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parametersnone', 1 ) or -- do this twice incase we have a first 1 without a last1
select_one( args, cfg.aliases[list_name .. '-Last'], 'redundant_parametersnone', 2 ) then
lastfirst=true;
end
வரி 2,165 ⟶ 2,437:
 
 
--[[--------------------------< IT SE _R PM AI RN A MT E T_ EN RA _M E X T _ W I K I L I NS KT >----------------------------------------
 
This function terminates a name list (author, contributor, editor) with a separator character (sepc) and a space
Return true if a parameter value has a string that begins and ends with square brackets [ and ] and the first
when the last character is not a sepc character or when the last three characters are not sepc followed by two
characters following the opening bracket obey the rules of a uri scheme (see check_url()). The test will also find
closing square brackets (close of a wikilink). When either of these is true, the name_list is terminated with a
external wikilinks that use protocol relative urls.
single space character.
 
]]
 
local function is_parameter_ext_wikilinkterminate_name_list (valuename_list, sepc)
if (string.sub (name_list,-1,-1) == sepc) or (string.sub (name_list,-3,-1) == sepc .. ']]') then -- if last name in list ends with sepc char
if value:match ("%[%[%a+:") then -- if a wikilink with namespace (interwiki)
return name_list .. " "; -- don't add another
return false;
elseif value:match ("%[%a[%a%d%+%.%-]*:.*%]") or value:match ("%[//.*%]") then -- does the param value contain an external wikilink?
-- elseif value:match ("%[%a[%a%d%+%.%-]*:%S.*%]") or value:match ("%[//.*%]") then -- does the param value contain an external wikilink?
return true;
else
return name_list .. sepc .. ' '; -- otherwise terninate the name list
return false;
end
end
 
 
--[[-------------------------< CF HO ER CM KA T _ FV O RL U M E _ UI RS LS U E >-----------------------------------------------------
 
returns the concatenation of the formatted volume and issue parameters as a single string; or formatted volume
loop through a list of parameters and their values. Look at the value and if it has an external link, emit an error message.
or formatted issue, or an empty string if neither are set.
 
]]
local function format_volume_issue (volume, issue, cite_class, origin, sepc, lower)
if not is_set (volume) and not is_set (issue) then
return '';
end
if 'magazine' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then
if is_set (volume) and is_set (issue) then
return wrap_msg ('vol-no', {sepc, volume, issue}, lower);
elseif is_set (volume) then
return wrap_msg ('vol', {sepc, volume}, lower);
else
return wrap_msg ('issue', {sepc, issue}, lower);
end
end
local vol = '';
if is_set (volume) then
if (4 < mw.ustring.len(volume)) then
vol = substitute (cfg.messages['j-vol'], {sepc, volume});
else
vol = wrap_style ('vol-bold', hyphen_to_dash(volume));
end
end
if is_set (issue) then
return vol .. substitute (cfg.messages['j-issue'], issue);
end
return vol;
end
 
 
local function check_for_url (parameter_list)
--[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >-----------------------------------------
local error_message = '';
 
for k, v in pairs (parameter_list) do -- for each parameter in the list
adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings.
if is_parameter_ext_wikilink (v) then -- look at the value; if there is a url add an error message
The return order is:
if is_set(error_message) then -- once we've added the first portion of the error message ...
page, pages, sheet, sheets
error_message=error_message .. ", "; -- ... add a comma space separator
 
Singular has priority over plural when both are provided.
 
]]
 
local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower)
if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators
if is_set (sheet) then
if 'journal' == origin then
return '', '', wrap_msg ('j-sheet', sheet, lower), '';
else
return '', '', wrap_msg ('sheet', {sepc, sheet}, lower), '';
end
elseif is_set (sheets) then
if 'journal' == origin then
return '', '', '', wrap_msg ('j-sheets', sheets, lower);
else
return '', '', '', wrap_msg ('sheets', {sepc, sheets}, lower);
end
error_message=error_message .. "&#124;" .. k .. "="; -- add the failed parameter
end
end
 
if is_set (error_message) then -- done looping, if there is an error message, display it
local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'journal' == origin);
table.insert( z.message_tail, { set_error( 'param_has_ext_link', {error_message}, true ) } );
 
if is_set (page) then
if is_journal then
return substitute (cfg.messages['j-page(s)'], page), '', '', '';
elseif not nopp then
return substitute (cfg.messages['p-prefix'], {sepc, page}), '', '', '';
else
return substitute (cfg.messages['nopp'], {sepc, page}), '', '', '';
end
elseif is_set(pages) then
if is_journal then
return substitute (cfg.messages['j-page(s)'], pages), '', '', '';
elseif tonumber(pages) ~= nil and not nopp then -- if pages is only digits, assume a single page number
return '', substitute (cfg.messages['p-prefix'], {sepc, pages}), '', '';
elseif not nopp then
return '', substitute (cfg.messages['pp-prefix'], {sepc, pages}), '', '';
else
return '', substitute (cfg.messages['nopp'], {sepc, pages}), '', '';
end
end
return '', '', '', ''; -- return empty strings
end
 
 
--[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
வரி 2,219 ⟶ 2,557:
]]
local A = argument_wrapper( args );
 
local i
 
local PPrefix = A['PPrefix']
local PPPrefix = A['PPPrefix']
local NoPP = A['NoPP']
if is_set (NoPP) and is_valid_parameter_value (NoPP, 'nopp', cfg.keywords ['yes_true_y']) then
PPPrefix = ''; -- unset these, prefix if used is in |page= or |pages=
PPrefix = '';
else
NoPP = nil; -- unset, used as a flag later
end
-- Pick out the relevant fields from the arguments. Different citation templates
-- define different field names for the same underlying things.
வரி 2,270 ⟶ 2,598:
 
local t = {}; -- translators list from |translator-lastn= / translator-firstn= pairs
local Translators; -- assembled trnaslatorstranslators name list
t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn=
local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs
local Contributors; -- assembled contributors name list
local Contribution = A['Contribution'];
if in_array(config.CitationClass, {"book","citation"}) and not is_set(A['Periodical']) then -- |contributor= and |contribution= only supported in book cites
c = extract_names (args, 'ContributorList'); -- fetch contributor list from |contributorn= / |contributor-lastn=, -firstn=, -linkn=, -maskn=
if 0 < #c then
if not is_set (Contribution) then -- |contributor= requires |contribution=
table.insert( z.message_tail, { set_error( 'contributor_missing_required_param', 'contribution')}); -- add missing contribution error message
c = {}; -- blank the contributors' table; it is used as a flag later
end
if 0 == #a then -- |contributor= requires |author=
table.insert( z.message_tail, { set_error( 'contributor_missing_required_param', 'author')}); -- add missing author error message
c = {}; -- blank the contributors' table; it is used as a flag later
end
end
else -- if not a book cite
if select_one (args, cfg.aliases['ContributorList-Last'], 'redundant_parameters', 1 ) then -- are there contributor name list parameters?
table.insert( z.message_tail, { set_error( 'contributor_ignored')}); -- add contributor ignored error message
end
Contribution = nil; -- unset
end
 
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
வரி 2,290 ⟶ 2,641:
local TitleNote = A['TitleNote'];
local TitleLink = A['TitleLink'];
if is_set (TitleLink) and false == link_param_ok (TitleLink) then
table.insert( z.message_tail, { set_error( 'bad_paramlink', A:ORIGIN('TitleLink'))}); -- url or wikilink in |title-link=;
end
 
local Chapter = A['Chapter'];
local ScriptChapter = A['ScriptChapter'];
வரி 2,307 ⟶ 2,662:
local ConferenceURLorigin = A:ORIGIN('ConferenceURL'); -- get name of parameter that holds ConferenceURL
local Periodical = A['Periodical'];
local Periodical_origin = A:ORIGIN('Periodical'); -- get the name of the periodical parameter
 
local Series = A['Series'];
local Volume = A['Volume'];
local Issue = A['Issue']Volume;
local Issue;
local Page;
local Pages;
local At;
 
if in_array (config.CitationClass, cfg.templates_using_volume) and not ('conference' == config.CitationClass and not is_set (Periodical)) then
Volume = A['Volume'];
end
if in_array (config.CitationClass, cfg.templates_using_issue) and not (in_array (config.CitationClass, {'conference', 'map'}) and not is_set (Periodical))then
Issue = A['Issue'];
end
local Position = '';
if not in_array (config.CitationClass, cfg.templates_not_using_page) then
local Page = A['Page'];
Page = A['Page'];
local Pages = hyphen_to_dash( A['Pages'] );
local At Pages = hyphen_to_dash( A['AtPages'] );
At = A['At'];
end
 
local Edition = A['Edition'];
வரி 2,370 ⟶ 2,739:
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
 
வரி 2,379 ⟶ 2,748:
 
--local variables that are not cs1 parameters
local use_lowercase; -- controls capitalization of certain static text
local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language
local anchor_year; -- used in the CITEREF identifier
local COinS_date = {}; -- usedholds indate info extracted from |date= for the COinS metadata by Module:Date verification
 
-- set default parameter values defined by |mode= parameter. If |mode= is empty or omitted, use CitationClass to set these values
வரி 2,408 ⟶ 2,777:
end
 
-- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it)
select_one( args, {'page', 'p', 'pp', 'pages', 'at', 'sheet', 'sheets'}, 'redundant_parameters' ); -- this is a dummy call simply to get the error message and category
 
local NoPP = A['NoPP']
if is_set (NoPP) and is_valid_parameter_value (NoPP, 'nopp', cfg.keywords ['yes_true_y']) then
NoPP = true;
else
NoPP = nil; -- unset, used as a flag later
end
 
if is_set(Page) then
if is_set(Pages) or is_set(At) then
Page = Page .. " " .. set_error('extra_pages'); -- add error message
Pages = ''; -- unset the others
At = '';
end
extra_text_in_page_check (Page, NoPP); -- add this page to maint cat if |page= value begins with what looks like p. or pp.
elseif is_set(Pages) then
if is_set(At) then
Pages = Pages .. " " .. set_error('extra_pages'); -- add error messages
At = ''; -- unset
end
extra_text_in_page_check (Pages, NoPP); -- add this page to maint cat if |pagepages= value begins with what looks like p. or pp.
end
 
வரி 2,475 ⟶ 2,851:
 
-- Special case for cite techreport.
if (config.CitationClass == "techreport") then -- special case for cite techreport
if is_set(IssueA['Number']) then -- cite techreport uses 'number', which other citations aliasealias to 'issue'
if not is_set(ID) then -- can we use ID for the "number"?
ID = IssueA['Number']; -- yes, use it
else -- ID has a value so emit error message
Issue = ""; -- unset Issue so that "number" isn't duplicated in the rendered citation or COinS metadata
-- ID = ID .. " " .. set_error('redundant_parameters', '<code>&#124;id=</code> and <code>&#124;number=</code>');
else -- can't use ID so emit error message
table.insert( z.message_tail, { set_error('redundant_parameters', {wrap_style ('parameter', 'id') .. ' and ' .. wrap_style ('parameter', 'number')}, true )});
ID = ID .. " " .. set_error('redundant_parameters', '<code>&#124;id=</code> and <code>&#124;number=</code>');
end
end
வரி 2,521 ⟶ 2,897:
if (config.CitationClass == "mailinglist") then
Periodical = A ['MailingList'];
elseif 'mailinglist' == A:ORIGIN('Periodical') then
Periodical = ''; -- unset because mailing list is only used for cite mailing list
end
 
வரி 2,569 ⟶ 2,947:
local AirDate = A['AirDate'];
local SeriesLink = A['SeriesLink'];
if is_set (SeriesLink) and false == link_param_ok (SeriesLink) then
table.insert( z.message_tail, { set_error( 'bad_paramlink', A:ORIGIN('SeriesLink'))});
end
local Network = A['Network'];
local Station = A['Station'];
local s, n = {}, {};
 
-- do common parameters first
if is_set(Network) then table.insert(n, Network); end
வரி 2,578 ⟶ 2,958:
ID = table.concat(n, sepc .. ' ');
if not is_set (Date) and is_set (AirDate) then -- promote airdate or Began/Ended to date
ifDate is_set= (AirDate) then;
Date = AirDate;
end
end
 
வரி 2,639 ⟶ 3,017:
end
if first_set ({AccessDate, At, Chapter, Format, Page, Pages, Periodical, PublisherName, URL, -- a crude list of parameters that are not supported by cite arxiv
ID_list['ASIN'], ID_list['BIBCODE'], ID_list['DOI'], ID_list['ISBN'], ID_list['ISSN'],
ID_list['JFM'], ID_list['JSTOR'], ID_list['LCCN'], ID_list['MR'], ID_list['OCLC'], ID_list['OL'],
ID_list['OSTI'], ID_list['PMC'], ID_list['PMID'], ID_list['RFC'], ID_list['SSRN'], ID_list['USENETID'], ID_list['ZBL']},27) then
table.insert( z.message_tail, { set_error( 'arxiv_params_not_supported', {}, true ) } ); -- add error message
 
வரி 2,656 ⟶ 3,034:
 
-- handle type parameter for those CS1 citations that have default values
 
if in_array(config.CitationClass, {"AV-media-notes", "DVD-notes", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then
TitleType = set_titletype (config.CitationClass, TitleType);
வரி 2,665 ⟶ 3,042:
 
if is_set(TitleType) then -- if type parameter is specified
TitleType = " substitute(" cfg..messages['type'], TitleType .. ")"; -- display it in parentheses
end
 
வரி 2,678 ⟶ 3,055:
end
 
if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation
 
--[[
வரி 2,689 ⟶ 3,066:
local error_message = '';
-- AirDate has been promoted to Date so not necessary to check it
anchor_year, COinS_date, error_message = dates({['access-date']=AccessDate, ['archive-date']=ArchiveDate, ['date']=Date, ['doi-broken-date']=DoiBroken,
['embargo']=Embargo, ['lay-date']=LayDate, ['publication-date']=PublicationDate, ['year']=Year}, COinS_date);
 
if is_set (Year) and is_set (Date) then -- both |date= and |year= not normally needed;
வரி 2,725 ⟶ 3,102:
not is_set(TransTitle) and
not is_set(ScriptTitle) then
if 'episode' == config.CitationClass then -- special case for cite episode; TODO: is there a better way to do this?
table.insert( z.message_tail, { set_error( 'citation_missing_title', {'series'}, true ) } );
else
வரி 2,732 ⟶ 3,109:
end
if 'none' == Title and is_set(Periodical) and notin_array (( config.CitationClass, == "encyclopaedia"{'journal', 'citation'}) orand is_set (Periodical) config.CitationClassand 'journal' == "citation" and is_set A:ORIGIN(Encyclopedia))'Periodical') then -- special case for journal cites
Title = ''; -- set title to empty string
add_maint_cat ('untitled');
end
 
check_for_url ({['title']=Title, ['chapter']=Chapter, ['work']=Periodical}); -- addsadd error message when any of these parameters containcontains a URL
['title']=Title,
[A:ORIGIN('Chapter')]=Chapter,
[A:ORIGIN('Periodical')]=Periodical,
[A:ORIGIN('PublisherName')] = PublisherName,
});
 
-- COinS metadata (see <http://ocoins.info/>) for automated parsing of citation information.
வரி 2,752 ⟶ 3,134:
end
end
local coins_author = a; -- default for coins rft.au
if 0 < #c then -- but if contributor list
coins_author = c; -- use that instead
end
 
-- this is the function call to COinS()
local OCinSoutput = COinS({
['Periodical'] = Periodical,
['Encyclopedia'] = Encyclopedia,
['Chapter'] = make_coins_title (coins_chapter, ScriptChapter), -- Chapter and ScriptChapter stripped of bold / italic wikimarkup
['Map'] = Map,
['Degree'] = Degree; -- cite thesis only
['Title'] = make_coins_title (coins_title, ScriptTitle), -- Title and ScriptTitle stripped of bold / italic wikimarkup
['PublicationPlace'] = PublicationPlace,
['Date'] = first_set(COinS_date.rftdate, Date), -- COinS_date has correctly formatted date if Date is valid; any reason to keep Date here? Should we be including invalid dates in metadata?
['Season'] = COinS_date.rftssn,
['Chron'] = COinS_date.rftchron or (not COinS_date.rftdate and Date) or '', -- chron but if not set and invalid date format use Date; keep this last bit?
['Series'] = Series,
['Volume'] = Volume,
['Issue'] = Issue,
['Pages'] = get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links
['Edition'] = Edition,
['PublisherName'] = PublisherName,
['URL'] = first_set ({ChapterURL, URL}, ChapterURL 2),
['Authors'] = acoins_author,
['ID_list'] = ID_list,
['RawPage'] = this_page.prefixedText,
வரி 2,780 ⟶ 3,171:
if 'newsgroup' == config.CitationClass then
if is_set (PublisherName) then
PublisherName = '[[Usenetsubstitute (cfg.messages['newsgroup|Newsgroup]]:&nbsp;' .. ], external_link( 'news:' .. PublisherName, PublisherName, A:ORIGIN('PublisherName') ));
end
end
வரி 2,810 ⟶ 3,201:
control.maximum = maximum;
last_first_list, EditorCount = list_people(control, e, editor_etal, 'editor');
 
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, 'translator'); -- et al not currently supported
end
do -- now do authorscontributors
control.maximum = #c; -- number of contributors
Contributors = list_people(control, c, false, 'contributor'); -- 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, 'author');
 
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
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
local last_first_list;
local maximum = A['DisplayAuthors'];
 
maximum , author_etal = get_display_authors_editors (maximum, #a, 'authors', author_etal);
 
local control = {
format = NameListFormat, -- empty string or 'vanc'
maximum = maximum,
lastauthoramp = LastAuthorAmp,
page_name = this_page.text -- get current page name so that we don't wikilink to it via authorlinkn
};
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
 
local EditorCount; -- used only for choosing {ed.) or (eds.) annotation at end of editor name-list
do
local last_first_list;
local maximum = A['DisplayEditors'];
 
maximum , editor_etal = get_display_authors_editors (maximum, #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
 
local control = {
format = NameListFormat, -- empty string or 'vanc'
maximum = maximum,
lastauthoramp = LastAuthorAmp,
page_name = this_page.text -- get current page name so that we don't wikilink to it via editorlinkn
};
 
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
]]
 
-- apply |[xx-]format= styling; at the end, these parameters hold correctly styled format annotation,
-- an error message if the associated url is not set, or an empty string for concatenation
ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url');
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url');
ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url');
Format = style_format (Format, URL, 'format', 'url');
LayFormat = style_format (LayFormat, LayURL, 'lay-format', 'lay-url');
TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl');
 
-- special case for chapter format so no error message or cat when chapter not supported
if not (in_array(config.CitationClass, {'web','news','journal', 'magazine', 'pressrelease','podcast', 'newsgroup', 'arxiv'}) or
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia))) then
ChapterFormat = style_format (ChapterFormat, ChapterURL, 'chapter-format', 'chapter-url');
end
 
if not is_set(URL) then --and
if in_array(config.CitationClass, {"web","podcast", "mailinglist"}) then -- Test if cite web or cite podcast |url= is missing or empty
-- not is_set(ArchiveURL) then --and -- prevents format_missing_url error from registering
-- not is_set(ConferenceURL) and -- TODO: keep this here? conference as part of cite web or cite podcast?
-- not is_set(TranscriptURL) then -- TODO: remove? |transcript-url= and |transcript= has separate test
-- Test if cite web or cite podcast |url= is missing or empty
if in_array(config.CitationClass, {"web","podcast", "mailinglist"}) then
table.insert( z.message_tail, { set_error( 'cite_web_url', {}, true ) } );
end
வரி 2,959 ⟶ 3,277:
end
 
local OriginalURL, OriginalURLorigin, OriginalFormat; -- TODO: swap chapter and title here so that archive applies to most specific if both are set?
DeadURL = DeadURL:lower(); -- used later when assembling archived text
if is_set( ArchiveURL ) then
if is_set (URL) then
OriginalURL = URL; -- save copy of original source URL
OriginalURLorigin = URLorigin; -- name of url parameter for error messages
OriginalFormat = Format; -- and original |format=
if 'no' ~= DeadURL then -- if URL set then archive-url applies to it
வரி 2,972 ⟶ 3,291:
elseif is_set (ChapterURL) then -- URL not set so if chapter-url is set apply archive url to it
OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text
OriginalURLorigin = ChapterURLorigin; -- name of chapter-url parameter for error messages
OriginalFormat = ChapterFormat; -- and original |format=
if 'no' ~= DeadURL then
ChapterURL = ArchiveURL -- swap-in the archive's url
URLoriginChapterURLorigin = A:ORIGIN('ArchiveURL') -- name of archive -url parameter for error messages
ChapterFormat = ArchiveFormat or ''; -- swap in archive's format
end
வரி 2,981 ⟶ 3,301:
end
 
if in_array(config.CitationClass, {"'web"',"'news"',"'journal"'," 'magazine', 'pressrelease"',"'podcast"', "'newsgroup"', 'arxiv'}) or -- if any of the 'periodical' cites except encyclopedia
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) then
local chap_param;
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
if is_set (Chapter) then -- get a parameter name from one of these chapter related meta-parameters
table.insert( z.message_tail, { set_error( 'chapter_ignored', {A:ORIGIN ('Chapter')}, true ) } ); -- add error message
chap_param = A:ORIGIN ('Chapter')
Chapter = ''; -- set them to empty string to be safe with concatenation
elseif is_set (TransChapter) then
chap_param = A:ORIGIN ('TransChapter')
elseif is_set (ChapterURL) then
chap_param = A:ORIGIN ('ChapterURL')
elseif is_set (ScriptChapter) then
chap_param = A:ORIGIN ('ScriptChapter')
else is_set (ChapterFormat)
chap_param = A:ORIGIN ('ChapterFormat')
end
 
if is_set (chap_param) then -- if we found one
table.insert( z.message_tail, { set_error( 'chapter_ignored', {chap_param}, true ) } ); -- add error message
Chapter = ''; -- and set them to empty string to be safe with concatenation
TransChapter = '';
ChapterURL = '';
ScriptChapter = '';
ChapterFormat = '';
end
else -- otherwise, format chapter / article title
local no_quotes = false; -- default assume that we will be quoting the chapter parameter value
Chapter = format_chapter_title (ScriptChapter, Chapter, TransChapter, ChapterURL, ChapterURLorigin);
if is_set (Contribution) and 0 < #c then -- if this is a contribution with contributor(s)
if in_array (Contribution:lower(), cfg.keywords.contribution) then -- and a generic contribution title
no_quotes = true; -- then render it unquoted
end
end
 
Chapter = format_chapter_title (ScriptChapter, Chapter, TransChapter, ChapterURL, ChapterURLorigin, no_quotes); -- Contribution is also in Chapter
if is_set (Chapter) then
if 'map' == config.CitationClass and is_set (TitleType) then
வரி 2,997 ⟶ 3,338:
end
Chapter = Chapter .. ChapterFormat .. sepc .. ' ';
elseif is_set (ChapterFormat) then -- |chapter= not set but |chapter-format= is so ...
Chapter = ChapterFormat .. sepc .. ' '; -- ... ChapterFormat has error message, we want to see it
end
end
வரி 3,005 ⟶ 3,348:
end
 
if in_array(config.CitationClass, {"'web"',"'news"',"'journal"'," 'magazine', 'pressrelease"',"'podcast"', "'newsgroup"', "'mailinglist"', 'arxiv'}) or
('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or
('map' == config.CitationClass and is_set (Periodical)) then -- special case for cite map when the map is in a periodical treat as an article
வரி 3,035 ⟶ 3,378:
if is_set(Title) then
if not is_set(TitleLink) and is_set(URL) then
Title = external_link( URL, Title, URLorigin ) .. TransError .. Format;
URL = "";
Format = "";
வரி 3,049 ⟶ 3,392:
if is_set (Conference) then
if is_set (ConferenceURL) then
Conference = external_link( ConferenceURL, Conference, ConferenceURLorigin );
end
Conference = sepc .. " " .. Conference .. ConferenceFormat;
வரி 3,058 ⟶ 3,401:
if not is_set(Position) then
local Minutes = A['Minutes'];
local Time = A['Time'];
 
if is_set(Minutes) then
if is_set (Time) then
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', 'minutes') .. ' and ' .. wrap_style ('parameter', 'time')}, true ) } );
end
Position = " " .. Minutes .. " " .. cfg.messages['minutes'];
else
local Time = A['Time'];
if is_set(Time) then
local TimeCaption = A['TimeCaption']
வரி 3,076 ⟶ 3,423:
Position = " " .. Position;
At = '';
end
if not is_set(Page) then
if is_set(Pages) then
if is_set(Periodical) and
not in_array(config.CitationClass, {"encyclopaedia","web","book","news","podcast"}) then
Pages = ": " .. Pages;
elseif tonumber(Pages) ~= nil then
Pages = sepc .." " .. PPrefix .. Pages;
else
Pages = sepc .." " .. PPPrefix .. Pages;
end
end
else
if is_set(Periodical) and
not in_array(config.CitationClass, {"encyclopaedia","web","book","news","podcast"}) then
Page = ": " .. Page;
else
Page = sepc .." " .. PPrefix .. Page;
end
end
 
Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase);
if 'map' == config.CitationClass then -- cite map oddity done after COinS call (and with other in-source locators)
if is_set (Sheet) or is_set (Sheets) then
local err_msg1 = 'sheet=, &#124;sheets'; -- default error message in case any of page pages or at are set
local err_msg2;
if is_set (Page) or is_set (Pages) or is_set (At) then -- are any set?
err_msg2 = 'page=, &#124;pages=, &#124;at'; -- a generic error message
Page = ''; Pages = ''; At = '';
elseif is_set (Sheet) and is_set (Sheets) then -- if both are set make error message
err_msg1 = 'sheet';
err_msg2 = 'sheets';
end
if is_set (err_msg2) then
table.insert( z.message_tail, { set_error( 'redundant_parameters', {wrap_style ('parameter', err_msg1) .. ' and ' .. wrap_style ('parameter', err_msg2)}, true ) } ); -- add error message
end
if not is_set (Sheet) then -- do sheet static text and formatting; Sheet has priority over Sheets if both provided
if is_set (Sheets) then
if is_set (Periodical) then
Sheet = ": Sheets " .. Sheets; -- because Sheet has priority, no need to support both later on
else
Sheet = sepc .. " Sheets " .. Sheets;
end
end
else
if is_set (Periodical) then
Sheet = ": Sheet " .. Sheet;
else
Sheet = sepc .. " Sheet " .. Sheet;
end
end
end
end
 
At = is_set(At) and (sepc .. " " .. At) or "";
வரி 3,170 ⟶ 3,467:
Edition = '';
end
 
Issue = is_set(Issue) and (" (" .. Issue .. ")") or "";
Series = is_set(Series) and (sepc .. " " .. Series) or "";
OrigYear = is_set(OrigYear) and (" [" .. OrigYear .. "]") or "";
Agency = is_set(Agency) and (sepc .. " " .. Agency) or "";
 
Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase);
if is_set(Volume) then
if ( mw.ustring.len(Volume) > 4 )
then Volume = sepc .." " .. Volume;
else Volume = " <b>" .. hyphen_to_dash(Volume) .. "</b>";
end
end
 
------------------------------------ totally unrelated data
வரி 3,225 ⟶ 3,517:
 
if is_set(Quote) then
if Quote:sub(1,1) == '"' and Quote:sub(-1,-1) == '"' then -- if first and last characters of quote are quote marks
Quote = Quote:sub(2,-2); -- strip them off
end
Quote = sepc .." " .. wrap_style ('quoted-text', Quote ); -- wrap in <q>...</q> tags
PostScript = ""; -- CS1cs1|2 does not supply terminal punctuation when |quote= is set
end
வரி 3,241 ⟶ 3,533:
if sepc ~= "." then arch_text = arch_text:lower() end
Archived = sepc .. " " .. substitute( cfg.messages['archived-not-dead'],
{ external_link( ArchiveURL, arch_text, A:ORIGIN('ArchiveURL') ) .. ArchiveFormat, ArchiveDate } );
if not is_set(OriginalURL) then
Archived = Archived .. " " .. set_error('archive_missing_url');
வரி 3,248 ⟶ 3,540:
local arch_text = cfg.messages['archived-dead'];
if sepc ~= "." then arch_text = arch_text:lower() end
-- 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'], OriginalURLorigin ) .. OriginalFormat, ArchiveDate } ); -- format already styled
end
else
வரி 3,276 ⟶ 3,567:
end
if sepc == '.' then
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary'], A:ORIGIN('LayURL') ) .. LayFormat .. LaySource .. LayDate
else
Lay = sepc .. " " .. external_link( LayURL, cfg.messages['lay summary']:lower(), A:ORIGIN('LayURL') ) .. LayFormat .. LaySource .. LayDate
end
elseif is_set (LayFormat) then -- Test if |lay-format= is given without giving a |lay-url=
வரி 3,286 ⟶ 3,577:
if is_set(Transcript) then
if is_set(TranscriptURL) then
Transcript = external_link( TranscriptURL, Transcript, TranscriptURLorigin );
end
Transcript = sepc .. ' ' .. Transcript .. TranscriptFormat;
வரி 3,360 ⟶ 3,651:
-- not to keep reassigning to the same string variable over and over.
 
local tcommon;
local tcommon2; -- used for book cite when |contributor= is set
if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then
if is_set(Others) then Others = Others .. sepc .. " " end
tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series,
Language, Edition, Publisher, Agency, Volume, Issue}, sepc );
elseif in_array(config.CitationClass, {"book","citation"}) and not is_set(Periodical) then -- special cases for book cites
if is_set (Contributors) then -- when we are citing foreword, preface, introduction, etc
tcommon = safe_join( {Title, TitleNote}, sepc ); -- author and other stuff will come after this and before tcommon2
tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc );
else
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc );
end
 
elseif 'map' == config.CitationClass then -- special cases for cite map
if is_set (Chapter) then -- map in a book; TitleType is part of Chapter
tcommon = safe_join( {Title, Format, Edition, Scale, Series, Language, Cartography, Others, Publisher, Volume}, sepc );
elseif is_set (Periodical) then -- map in a periodical
tcommon = safe_join( {Title, TitleType, Format, Periodical, Scale, Series, Language, Cartography, Others, Publisher, Volume, Issue}, sepc );
else -- a sheet or stand-alone map
tcommon = safe_join( {Title, TitleType, Format, Edition, Scale, Series, Language, Cartography, Others, Publisher}, sepc );
வரி 3,379 ⟶ 3,680:
else -- all other CS1 templates
tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language,
Volume, Issue, Others, Edition, Publisher, Agency}, sepc );
end
வரி 3,390 ⟶ 3,691:
local idcommon = safe_join( { ID_list, URL, Archived, AccessDate, Via, SubscriptionRequired, Lay, Quote }, sepc );
local text;
local pgtext = Position .. Sheet .. Sheets .. Page .. Pages .. At;
 
if is_set(Date) then
if is_set (Authors) or is_set (Editors) then -- date follows authors or editors when authors not set
Date = " (" .. Date ..")" .. OrigYear .. sepc .. " "; -- in paranetheses
else -- neither of authors and editors set
if (string.sub(tcommon,-1,-1) == sepc) then -- if the last character of tcommon is sepc
Date = " " .. Date .. OrigYear; -- Date does not begin with sepc
else
Date = sepc .. " " .. Date .. OrigYear; -- Date begins with sepc
end
end
end
if is_set(Authors) then
if is_set(Coauthors) then
if 'vanc' == NameListFormat then -- separate authors and coauthors with proper name-list-separator
local sep = '; ';
Authors = Authors .. ', ' .. Coauthors;
if 'vanc' == NameListFormat then
else
sep = ', ';
Authors = Authors .. '; ' .. Coauthors;
end
Authors = Authors .. sep .. Coauthors;
end
if not is_set (Date) then -- when date is set it's in parentheses; no Authors termination
Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space
Date = " ("..Date..")" .. OrigYear .. sepc .. " "
elseif string.sub(Authors,-1,-1) == sepc then
Authors = Authors .. " "
else
Authors = Authors .. sepc .. " "
end
if is_set(Editors) then
local in_text = " ";
local post_text = "";
if is_set(Chapter) and 0 == #c then
in_text = in_text .. cfg.messages['in'] .. " "
if (sepc ~= '.') then in_text = in_text:lower() end -- lowercase for cs2
else
if EditorCount <= 1 then
வரி 3,419 ⟶ 3,728:
end
end
Editors = terminate_name_list (in_text .. Editors .. post_text, sepc); -- terminate with 0 or 1 sepc and a space
if (sepc ~= '.') then in_text = in_text:lower() end
end
Editors = in_text .. Editors .. post_text;
if is_set (Contributors) then -- book cite and we're citing the intro, preface, etc
if (string.sub(Editors,-1,-1) == sepc) or (string.sub(Editors,-3,-1) == sepc .. ']]') then -- if last editor name ends with sepc char
local by_text = sepc .. ' ' .. cfg.messages['by'] .. ' ';
Editors = Editors .. " "; -- don't add another
if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2
else
EditorsAuthors = Editorsby_text .. sepc .. " "Authors; -- otherwiseauthor follows title terninateso thetweak editorit listhere
if is_set (Editors) then -- when Editors make sure that Authors gets terminated
Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space
end
if not is_set (Date) then -- when date is set it's in parentheses; no Contributors termination
Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space
end
text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc );
else
text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc );
end
text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon }, sepc );
text = safe_join( {text, pgtext, idcommon}, sepc );
elseif is_set(Editors) then
if is_set(Date) then
வரி 3,436 ⟶ 3,751:
Editors = Editors .. ", " .. cfg.messages['editors'];
end
Date = " (" .. Date ..")" .. OrigYear .. sepc .. " "
else
if EditorCount <= 1 then
வரி 3,444 ⟶ 3,758:
end
end
text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc );
text = safe_join( {text, pgtext, idcommon}, sepc );
else
if is_set(Date) then
if ( string.sub(tcommon,-1,-1) ~= sepc )
then Date = sepc .." " .. Date .. OrigYear
else Date = " " .. Date .. OrigYear
end
end
if config.CitationClass=="journal" and is_set(Periodical) then
text = safe_join( {Chapter, Place, tcommon, pgtext, Date, idcommon}, sepc );
text = safe_join( {text, pgtext, Date, idcommon}, sepc );
else
text = safe_join( {Chapter, Place, tcommon, Date, pgtext, idcommon}, sepc );
text = safe_join( {text, pgtext, idcommon}, sepc );
end
end
வரி 3,479 ⟶ 3,784:
end
if is_set(Ref) and Ref:lower() ~= "none" then -- set reference anchor if appropriate
local id = Ref
if ( "'harv"' == Ref ) then
local namesnamelist = {} ; --table ofholds selected contributor, lastauthor, nameseditor &name yearlist
-- local year = first_set (Year, anchor_year); -- Year first for legacy citations and for YMD dates that require disambiguation
if #a > 0 then
local year = first_set ({Year, anchor_year}, 2); -- Year first for legacy citations and for YMD dates that require disambiguation
for i,v in ipairs(a) do
 
names[i] = v.last
if i#c ==> 40 then -- if there is a breakcontributor endlist
namelist = c; -- select it
end
elseif #ea > 0 then -- or an author list
namelist = a;
for i,v in ipairs(e) do
elseif #e > 0 then -- or an editor list
names[i] = v.last
namelist = e;
if i == 4 then break end
end
end
id = anchor_id (namelist, year); -- go make the CITEREF anchor
names[ #names + 1 ] = first_set(Year, anchor_year); -- Year first for legacy citations and for YMD dates that require disambiguation
id = anchor_id(names)
end
options.id = id;
வரி 3,514 ⟶ 3,817:
local empty_span = '<span style="display:none;">&nbsp;</span>';
-- Note: Using display: none on thenthe COinS span breaks some clients.
local OCinS = '<span title="' .. OCinSoutput .. '" class="Z3988">' .. empty_span .. '</span>';
text = text .. OCinS;
வரி 3,555 ⟶ 3,858:
end
 
--[[--------------------------< H A S _ I N V I S I B L E _ C H A R S >----------------------------------------
-- This is used by templates such as {{cite book}} to create the actual citation text.
 
This function searches a parameter's value for nonprintable or invisible characters. The search stops at the first match.
 
Sometime after this module is done with rendering a citation, some C0 control characters are replaced with the
replacement character. That replacement character is not detected by this test though it is visible to readers
of the rendered citation. This function will detect the replacement character when it is part of the wikisource.
 
Output of this function is an error message that identifies the character or the Unicode group that the character
belongs to along with its position in the parameter value.
 
]]
 
local function has_invisible_chars (param, v)
local position = '';
local i=1;
 
while cfg.invisible_chars[i] do
local char=cfg.invisible_chars[i][1] -- the character or group name
local pattern=cfg.invisible_chars[i][2] -- the pattern used to find it
position = mw.ustring.find (v, pattern) -- see if the parameter value contains characters that match the pattern
if position then
table.insert( z.message_tail, { set_error( 'invisible_char', {char, wrap_style ('parameter', param), position}, true ) } ); -- add error message
return; -- and done with this parameter
end
i=i+1; -- bump our index
end
end
 
 
--[[--------------------------< Z . C I T A T I O N >----------------------------------------------------------
 
This is used by templates such as {{cite book}} to create the actual citation text.
 
]]
 
function z.citation(frame)
local pframe = frame:getParent()
வரி 3,618 ⟶ 3,956:
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
if error_text ~= '' then
வரி 3,636 ⟶ 3,966:
end
end
 
for k, v in pairs( args ) do
has_invisible_chars (k, v)
end
return citation0( config, args)
end
"https://tamilar.wiki/w/Module:Citation/CS1" இலிருந்து மீள்விக்கப்பட்டது