Mô đun:Cite archive

require('strict')
local f = {};
local code_style="color:inherit; border:inherit; padding:inherit;";				-- used in styling error messages
----------------------------------------------------------------------------------------------
Whether variable is set or not.  A variable is set when it is not nil and not empty.
local function is_set( var )
	return not (var == nil or var == );
end
--------------------------------------------------------------------------------------
Choose one parameter value from a list of parameter values.  If more than one is set, emit error message.
local function select_one (list, args)
	local selected_param;
	local selected_val=;
	for param, value in pairs (list) do										-- loop through the list
		if not is_set (selected_param) then										-- if we have not yet selected a parameter value
			if is_set (value) then												-- is this value set?
				selected_val = value;											-- select it
				selected_param = param;											-- remember the name for possible error message
			end
		else
			if is_set (value) then												-- error message if we have selected and found another set parameter
				args.err_msg = string.format (' more than one of |%s= and |%s=', code_style, selected_param, code_style, param)
				break;
			end
		end
	end
	return selected_val or ;															-- return selected value or empty string if none set
end
----------------------------------------------------------------------------------------
Assembles last, first, link, or mask into a displayable author name.
local function make_name (last, first, link, mask)
	local name = last;
	
	if is_set (first) then
		name = name .. ', ' .. first;											-- concatenate first onto last
	end
	
	if is_set (link) then
		name =  .. name .. ;								-- form a wikilink around the name
	end
	
	if is_set (mask) then														-- mask this author
		mask = tonumber (mask);													-- because the value provided might not be a number
		if is_set (mask) then
			name = string.rep ('—', mask)										-- make a string that number length of mdashes
		end
	end
	
	return name;
end
--display-authors= is less than the number of author last names, displays the specified number of author names in last, first order followed by et al.
local function make_author_list (args, number_of_authors)
	local authors = ;
	local i = 1;
	local count;
	local etal = false;															-- when |display-authors= is same as number of authors in contributor list
	
	if is_set (args.display_authors) then
		if 'etal' == args.display_authors:lower():gsub(" '%.", ) then		-- the :gsub() portion makes 'etal' from a variety of 'et al.' spellings and stylings
			count = number_of_authors;											-- display all authors and ...
			etal = true;														-- ... append 'et al.'
		else
			count = tonumber (args.display_authors) or 0;						-- 0 if can't be converted to a number
			if 0 >= count then
				args.err_msg = string.format ('%s invalid |display-authors=; ', args.err_msg, code_style);
--				args.err_msg = args.err_msg .. ' invalid |display-authors=';	-- if zero, then emit error message
				count = number_of_authors;										-- and display all authors
			end
		end
		if count > number_of_authors then
			count = number_of_authors;											-- when |display-authors= is more than the number of authors, use the number of authors
		end
		if count ------------------------------------------------------------
This function formats |item= and, if present, |item-url= into the linked part and if present appends |date= and
type= with appropriate markup to complete the item portion of the citation.  This function assumes that item
has a value when it is called.
local function make_item (item, url, item_date, item_type)
	local output = {};															-- table of item bits
	if is_set (url) then
		item = string.format ('%s %s', url, item);							-- make item into an external wikilink
	end
	table.insert (output, string.format ('"%s"', item));						-- enclose in quotes and add to table
	if is_set (item_date) then
		table.insert (output, string.format ('(%s)', item_date));				-- enclose in parentheses and add to table
	end
	if is_set (item_type) then
		table.insert (output, string.format ('%s', item_type));				-- enclose in square brackets and add to table
	end
	
	return table.concat (output, ' ');											-- concatenate with space as separator
end
--pages= to complete the collection
portion of the citation.  This function assumes that collection has a value when it is called (because that is one
of the two required parameters)
local function make_collection (args)
	local output = {};															-- table of collections bits
	local collection = args.collection;
	if is_set (args.collectionURL) then
		collection = string.format ('%s %s', args.collectionURL, collection);				-- make collection into an external wikilink
	end
	table.insert (output, string.format ('%s', collection));					-- enclose in quotes and add to table
	if is_set (args.fonds) then
		table.insert (output, string.format ('Fonds: %s', args.fonds));			-- format and add to table
	end
	if is_set (args.series) then
		table.insert (output, string.format ('Series: %s', args.series));		-- format and add to table
	end
	if is_set (args.box) then
		table.insert (output, string.format ('Box: %s', args.box));				-- format and add to table
	end
	if is_set (args.file) then
		table.insert (output, string.format ('File: %s', args.file));			-- format and add to table
	end
	if is_set (args.itemID) then
		table.insert (output, string.format ('ID: %s', args.itemID));				-- format and add to table
	end
	
	if is_set (args.p) then
		table.insert (output, string.format ('%s%s', args.page_sep, args.p));
	elseif is_set (args.pp) then
		table.insert (output, string.format ('%s%s', args.pages_sep, args.pp));
	end      

	if is_set (args.p) and is_set (args.pp) then
		args.err_msg = string.format ('%s more than one of |page= and |pages=; ', args.err_msg, code_style, code_style);
	end

	return table.concat (output, ', ');											-- concatenate with comma space as separator
end
--institution= (a required parameter) has a value when it is called.
Unlike other groups of parameters, the required parameter is the 'last' and separator characters are not all the same.
local function make_location (location, repository, institution)
	local output = {};															-- table of location bits
	if is_set (location) then
		location = string.format ('%s: ', location);							-- format
	end
	if is_set (repository) then
		table.insert (output, repository);										-- and add to table
	end
	table.insert (output, institution);											-- and add to table
	
	return string.format ('%s%s', location, table.concat (output, ', '));		-- concatenate with comma space separators
end
--accession into the identifiers portion of the citation.  Neither of these
parameters are required.
local function make_identifiers (args)
	local output = {};															-- table ofidentifier bits
	if is_set (args.oclc) then
		table.insert (output, string.format ('OCLC  %s', args.oclc));
	end
	if is_set (args.accession) then
		table.insert (output, args.accession);
	end
	return table.concat (output, args.sepc .. ' ');								-- concatenate with sepc space as separator
end
--ref=harv.
local function _cite_archive (args)
	local cite_open_tag;														-- holds CITEREF and css
	local authors = ;															-- list of authors
	local identifiers = ;														-- OCLC and accession identifiers list
	local result = {};															-- the assembly of the citation's output
-- form the CITEREF anchor
	if 'harv' == args.ref then
		cite_open_tag = ;
	elseif is_set (args.ref) then
		cite_open_tag = ;
	else
		cite_open_tag = ;
	end
	if 0 ~= #args.last then														-- if there are author names
		table.insert (result, make_author_list (args, #args.last));				-- assemble author name list and add to result table
	end
	
	if is_set (args.item) then													-- if there is an item
		table.insert (result, make_item (args.item, args.itemURL, args.date, args.type));	-- build the item portion of the citation
	end
	table.insert (result, make_collection (args));								-- build the collection portion of the citation (|collection= is required)
	table.insert (result, make_location (args.location, args.repository, args.institution));	-- build the location portion of the citation (institution= is required)
	identifiers = make_identifiers (args);										-- build the identifiers (oclc and accession) portion of the citation
	if is_set (identifiers) then
		table.insert (result, identifiers);
	end
	if is_set (args.accessdate) then
		table.insert (result, args.retrieved .. args.accessdate);
	end
--	wrap error messages in span and add help link
	if is_set (args.err_msg) then
		args.err_msg = ' cite archive:' .. args.err_msg .. ' (help)';
	end
-- and put it all together and be done
	return string.format ('%s%s%s%s', cite_open_tag, table.concat (result, args.sepc .. ' '), args.ps, args.err_msg);
end
------------------------------------------------------------------------------
Entry point from  template.  Fetches parent frame parameters, does a bit of simple error checking
and calls _cite_archive() if required parameters are present.
function f.cite_archive (frame)
	local args = {
		err_msg = ,
		page_sep = "p. ",													-- cs1|2 style page(s) prefixes
		pages_sep = "pp. ",
		retrieved = 'Retrieved ',												-- cs1 style access date static text
		sepc = '.',																-- default to cs1 stylre
		ps = '.',																-- default to cs1 stylre
		last = {},																-- table of author last name values
		first = {},																-- table of author first name values
		link = {},																-- table of author link values
		mask = {},																-- table of author mask values
		citeref = {}															-- table of last names that will be used in making the CITEREF anchor
		}
	local pframe = frame:getParent();											-- get template's parameters
	args.item = pframe.args.item or ;											-- these are the 'item' group
	args.itemURL = pframe.args'item-url' or ;
	args.type = pframe.args.type or ;
	args.date = pframe.args.date or ;
	args.year = args.date:match ('%d%d%d%d') or ;								-- used in creation of the CITEREF anchor
	args.collection = pframe.args.collection or ;								-- these are the collection group
	args.collectionURL = pframe.args'collection-url' or ;
	args.fonds = pframe.args.fonds or ;
	args.series = pframe.args.series or ;
	args.file = pframe.args.file or ;
	args.box = pframe.args.box or ;
	args.itemID = pframe.args'item-id' or ;
	args.p = pframe.args.page or pframe.args.p or ;							-- if both are set, the singular is rendered
	args.pp = pframe.args.pages or pframe.args.pp or ;
	args.repository = pframe.args.repository or ;								-- these are the location group
	args.location = pframe.args.location or ;
	args.institution = pframe.args.institution or ;							-- required parameter
	args.oclc = pframe.args.oclc or ;											-- these are the identifiers group
	args.accession = pframe.args.accession or ;
	
	if not is_set (args.collection) then										-- check for required parameters
		args.err_msg = string.format (' |collection= required; ', code_style);
	end
	if not is_set (args.institution) then
		args.err_msg = string.format ('%s |institution= required; ', args.err_msg, code_style);
	end
	
	if is_set (args.err_msg) then												-- if set here, then we are missing one or both required parameters so quit
		return 'cite archive:' .. args.err_msg .. ' (help)';	-- with an error message
	end
																				-- standard cs1|2 parameters
	args.accessdate = pframe.args'access-date' or pframe.args.accessdate or ;
	args.ref = pframe.args.ref or ;
		
	args.display_authors = pframe.args'display-authors';						-- the number of author names to display
	args.last_author_amp = pframe.args'last-author-amp' or					-- yes only; |last-author-amp=no does not work
				pframe.args'lastauthoramp' or ;
	args.last_author_amp:lower();												-- make it case agnostic
	
	if is_set (pframe.args'last1') or is_set (pframe.args'last') or
		is_set (pframe.args'author1') or is_set (pframe.args'author') then	-- must have at least this to continue
		
		args.last1 = select_one ({											-- get first author's last name
			'last'=pframe.args.last,
			'last1' = pframe.args.last1,
			'author' = pframe.args.author,
			'author1' = pframe.args.author1}, args);
		args.citeref1 = args.last1;											-- add it to the citeref
		args.first1 = select_one ({											-- get first author's first name
			'first' = pframe.args.first,
			'first1' = pframe.args.first1}, args);
		args.link1 = select_one ({											-- get first author's article link
			'author-link' = pframe.args'author-link',
			'author-link1' = pframe.args'author-link1'}, args);
		args.mask1 = select_one ({											-- get first author's mask
			'author-mask' = pframe.args'author-mask',
			'author-mask1' = pframe.args'author-mask1'}, args);
	
		local i = 2;															-- index for the rest of the names
		while is_set (pframe.args'last'..i) or is_set (pframe.args'author'..i) do		-- loop through pframe.args and get the rest of the names
			args.lasti = pframe.args'last'..i or pframe.args'author'..i;				-- last names
			args.firsti = pframe.args'first'..i;							-- first names
			args.linki = pframe.args'author-link'..i;						-- author-links
			args.maski = pframe.args'author-mask'..i;						-- author-masks
			if 5 > i then
				args.citerefi = args.lasti;									-- collect first four last names for CITEREF anchor
			end
			i = i + 1															-- bump the index
		end
	end
	if 'cs2' == pframe.args.mode then
		args.ps = ;															-- set postscript character to empty string, cs2 mode
		args.sepc = ',';														-- set separator character to comma, cs2 mode
		if not is_set (args.ref) then											-- if not already set to something
			args.ref= 'harv';													-- for cs2, set to harv
		end
		args.retrieved = args.retrieved:lower();
	end
	return _cite_archive (args);											-- go render the citation
end
return f;