Line 5: |
Line 5: |
| ]] | | ]] |
| | | |
− | local dates, year_date_check, reformat_dates, date_hyphen_to_dash -- functions in Module:Citation/CS1/Date_validation | + | local dates, year_date_check, reformat_dates, date_hyphen_to_dash, -- functions in Module:Citation/CS1/Date_validation |
| + | date_name_xlate |
| | | |
| local is_set, in_array, substitute, error_comment, set_error, select_one, -- functions in Module:Citation/CS1/Utilities | | local is_set, in_array, substitute, error_comment, set_error, select_one, -- functions in Module:Citation/CS1/Utilities |
− | add_maint_cat, wrap_style, safe_for_italics, remove_wiki_link; | + | add_maint_cat, wrap_style, safe_for_italics, is_wikilink, make_wikilink; |
| | | |
| local z ={}; -- tables in Module:Citation/CS1/Utilities | | local z ={}; -- tables in Module:Citation/CS1/Utilities |
Line 54: |
Line 55: |
| end | | end |
| end | | end |
| + | |
| | | |
| --[[--------------------------< A D D _ P R O P _ C A T >-------------------------------------------------------- | | --[[--------------------------< A D D _ P R O P _ C A T >-------------------------------------------------------- |
| | | |
| Adds a category to z.properties_cats using names from the configuration file with additional text if any. | | Adds a category to z.properties_cats using names from the configuration file with additional text if any. |
| + | |
| + | foreign_lang_source and foreign_lang_source_2 keys have a language code appended to them so that multiple languages |
| + | may be categorized but multiples of the same language are not categorized. |
| | | |
| added_prop_cats is a table declared in page scope variables above | | added_prop_cats is a table declared in page scope variables above |
Line 66: |
Line 71: |
| if not added_prop_cats [key] then | | if not added_prop_cats [key] then |
| added_prop_cats [key] = true; -- note that we've added this category | | added_prop_cats [key] = true; -- note that we've added this category |
| + | key = key:gsub ('(foreign_lang_source_?2?)%a%a%a?', '%1'); -- strip lang code from keyname |
| table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table | | table.insert( z.properties_cats, substitute (cfg.prop_cats [key], arguments)); -- make name then add to table |
| end | | end |
| end | | end |
| + | |
| | | |
| --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- | | --[[--------------------------< A D D _ V A N C _ E R R O R >---------------------------------------------------- |
Line 126: |
Line 133: |
| the first character of the whole domain name including subdomains must be a letter or a digit | | the first character of the whole domain name including subdomains must be a letter or a digit |
| internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490 | | internationalized domain name (ascii characters with .xn-- ASCII Compatible Encoding (ACE) prefix xn-- in the tld) see https://tools.ietf.org/html/rfc3490 |
− | single-letter/digit second-level domains in the .org TLD | + | single-letter/digit second-level domains in the .org and .cash TLDs |
| q, x, and z SL domains in the .com TLD | | q, x, and z SL domains in the .com TLD |
| i and q SL domains in the .net TLD | | i and q SL domains in the .net TLD |
Line 146: |
Line 153: |
| | | |
| if not domain:match ('^[%a%d]') then -- first character must be letter or digit | | if not domain:match ('^[%a%d]') then -- first character must be letter or digit |
| + | return false; |
| + | end |
| + | |
| + | if domain:match ('^%a+:') then -- hack to detect things that look like s:Page:Title where Page: is namespace at wikisource |
| return false; | | return false; |
| end | | end |
Line 153: |
Line 164: |
| elseif domain:match ('%f[%a%d][%a%d][%a%d%-]+[%a%d]%.xn%-%-[%a%d]+$') then -- internationalized domain name with ACE prefix | | elseif domain:match ('%f[%a%d][%a%d][%a%d%-]+[%a%d]%.xn%-%-[%a%d]+$') then -- internationalized domain name with ACE prefix |
| return true; | | return true; |
− | elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character .org hostname | + | elseif domain:match ('%f[%a%d][%a%d]%.cash$') then -- one character/digit .cash hostname |
| + | return true; |
| + | elseif domain:match ('%f[%a%d][%a%d]%.org$') then -- one character/digit .org hostname |
| return true; | | return true; |
| elseif domain:match ('%f[%a][qxz]%.com$') then -- assigned one character .com hostname (x.com times out 2015-12-10) | | elseif domain:match ('%f[%a][qxz]%.com$') then -- assigned one character .com hostname (x.com times out 2015-12-10) |
Line 249: |
Line 262: |
| return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid url | | return not is_url (scheme, domain); -- return true if value DOES NOT appear to be a valid url |
| end | | end |
| + | |
| | | |
| --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- | | --[[--------------------------< L I N K _ T I T L E _ O K >--------------------------------------------------- |
Line 376: |
Line 390: |
| ['\n'] = ' ' } ); | | ['\n'] = ' ' } ); |
| end | | end |
| + | |
| | | |
| --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- | | --[[--------------------------< E X T E R N A L _ L I N K >---------------------------------------------------- |
Line 388: |
Line 403: |
| local path; | | local path; |
| local base_url; | | local base_url; |
− |
| + | |
| if not is_set( label ) then | | if not is_set( label ) then |
| label = URL; | | label = URL; |
Line 404: |
Line 419: |
| if path then -- if there is a path portion | | if path then -- if there is a path portion |
| path = path:gsub ('[%[%]]', {['[']='%5b',[']']='%5d'}); -- replace '[' and ']' with their percent encoded values | | path = path:gsub ('[%[%]]', {['[']='%5b',[']']='%5d'}); -- replace '[' and ']' with their percent encoded values |
− | URL=domain..path; -- and reassemble | + | URL = table.concat ({domain, path}); -- and reassemble |
| end | | end |
− |
| |
− | if is_set (access) then -- access level (subscription, registration, limited)
| |
− | local label_head = '';
| |
− | local label_tail;
| |
− | local markup = ''; -- can't start a span inside italic markup and end it outside the italic markup
| |
| | | |
− | label = safe_for_url (label); -- replace square brackets and newlines (is this necessary? already done above?)
| + | base_url = table.concat({ "[", URL, " ", safe_for_url (label), "]" }); -- assemble a wikimarkup url |
− | if label:match ("(.*)%s+(.+)('''?)$") then -- for italicized titles (cite book, etc)
| |
− | label_head, label_tail, markup = label:match ("(.*)%s+(.+)('''?)$"); -- split the label at the right-most space; separate the markup
| |
− | elseif label:match ("(.*)%s+(.+)$") then -- for upright titles (journal, news, magazine, etc)
| |
− | label_head, label_tail = label:match ("(.*)%s+(.+)$"); -- split the label at the right-most space; no markup
| |
− | elseif label:match ("(.+)('''?)$") then -- single word label with markup
| |
− | label_tail, markup = label:match ("(.+)('''?)$"); -- save label text as label tail; separate the markup
| |
− | else
| |
− | label_tail = label;
| |
− | end
| |
| | | |
− | base_url = table.concat (
| + | if is_set (access) then -- access level (subscription, registration, limited) |
− | {
| + | base_url = substitute (cfg.presentation['ext-link-access-signal'], {cfg.presentation[access].class, cfg.presentation[access].title, base_url}); -- add the appropriate icon |
− | '<span class="plainlinks">[', -- opening css
| |
− | URL, -- the url
| |
− | ' ', -- the required space
| |
− | label_head, -- all but the last word of the label
| |
− | ' <span class="nowrap">', -- nowrap css for the last word and the signal icon
| |
− | label_tail, -- last (or only) word of the label inside the span
| |
− | '<span style="padding-left:0.15em">', -- signal spacing css
| |
− | cfg.presentation[access], -- the appropriate icon
| |
− | '</span></span>', -- close signal spacing and nowrap spans
| |
− | markup, -- insert italic markup if any
| |
− | ']</span>' -- close the plain links span
| |
− | });
| |
− | else
| |
− | base_url = table.concat({ "[", URL, " ", safe_for_url( label ), "]" }); -- no signal markup
| |
| end | | end |
| | | |
− | return table.concat({ base_url, error_str }); | + | return table.concat ({base_url, error_str}); |
| end | | end |
| | | |
Line 462: |
Line 449: |
| end | | end |
| | | |
− | --[[--------------------------< K E R N _ Q U O T E S >--------------------------------------------------------
| |
| | | |
− | Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote mark contained in a |title= or |chapter= parameter's value. | + | --[=[-------------------------< K E R N _ Q U O T E S >-------------------------------------------------------- |
| + | |
| + | Apply kerning to open the space between the quote mark provided by the Module and a leading or trailing quote |
| + | mark contained in a |title= or |chapter= parameter's value. |
| + | |
| This function will positive kern either single or double quotes: | | This function will positive kern either single or double quotes: |
| "'Unkerned title with leading and trailing single quote marks'" | | "'Unkerned title with leading and trailing single quote marks'" |
Line 470: |
Line 460: |
| Double single quotes (italic or bold wikimarkup) are not kerned. | | Double single quotes (italic or bold wikimarkup) are not kerned. |
| | | |
− | Replaces unicode quotemarks with typewriter quote marks regardless of the need for kerning. | + | Replaces unicode quotemarks in plain text or in the label portion of a [[L|D]] style wikilink with typewriter |
| + | quote marks regardless of the need for kerning. Unicode quote marks are not replaced in simple [[D]] wikilinks. |
| | | |
| Call this function for chapter titles, for website titles, etc; not for book titles. | | Call this function for chapter titles, for website titles, etc; not for book titles. |
| | | |
− | ]] | + | ]=] |
| | | |
| local function kern_quotes (str) | | local function kern_quotes (str) |
| local cap=''; | | local cap=''; |
| local cap2=''; | | local cap2=''; |
− | -- TODO: move this elswhere so that all title-holding elements get these quote marks replaced?
| + | local wl_type, label, link; |
− | -- str= mw.ustring.gsub (str, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark)
| + | |
− | -- str= mw.ustring.gsub (str, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark)
| + | wl_type, label, link = is_wikilink (str); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] |
| | | |
− | cap, cap2 = str:match ("^([\"\'])([^\'].+)"); -- match leading double or single quote but not double single quotes | + | if 1 == wl_type then -- [[D]] simple wikilink with or without quote marks |
− | if is_set (cap) then
| + | if mw.ustring.match (str, '%[%[[\"“”\'‘’].+[\"“”\'‘’]%]%]') then -- leading and trailing quote marks |
− | str = substitute (cfg.presentation['kern-left'], {cap, cap2});
| + | str = substitute (cfg.presentation['kern-wl-both'], str); |
− | end
| + | elseif mw.ustring.match (str, '%[%[[\"“”\'‘’].+%]%]') then -- leading quote marks |
| + | str = substitute (cfg.presentation['kern-wl-left'], str); |
| + | elseif mw.ustring.match (str, '%[%[.+[\"“”\'‘’]%]%]') then -- trailing quote marks |
| + | str = substitute (cfg.presentation['kern-wl-right'], str); |
| + | end |
| + | |
| + | else -- plain text or [[L|D]]; text in label variable |
| + | label= mw.ustring.gsub (label, '[“”]', '\"'); -- replace “” (U+201C & U+201D) with " (typewriter double quote mark) |
| + | label= mw.ustring.gsub (label, '[‘’]', '\''); -- replace ‘’ (U+2018 & U+2019) with ' (typewriter single quote mark) |
| | | |
− | cap, cap2 = str:match ("^(.+[^\'])([\"\'])$") | + | cap, cap2 = mw.ustring.match (label, "^([\"\'])([^\'].+)"); -- match leading double or single quote but not doubled single quotes (italic markup) |
− | if is_set (cap) then
| + | if is_set (cap) then |
− | str = substitute (cfg.presentation['kern-right'], {cap, cap2});
| + | label = substitute (cfg.presentation['kern-left'], {cap, cap2}); |
| + | end |
| + | |
| + | cap, cap2 = mw.ustring.match (label, "^(.+[^\'])([\"\'])$") -- match trailing double or single quote but not doubled single quotes (italic markup) |
| + | if is_set (cap) then |
| + | label = substitute (cfg.presentation['kern-right'], {cap, cap2}); |
| + | end |
| + | |
| + | if 2 == wl_type then |
| + | str = make_wikilink (link, label); -- reassemble the wikilink |
| + | else |
| + | str = label; |
| + | end |
| end | | end |
| return str; | | return str; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- | | --[[--------------------------< F O R M A T _ S C R I P T _ V A L U E >---------------------------------------- |
Line 529: |
Line 541: |
| end | | end |
| -- if we get this far we have prefix and script | | -- if we get this far we have prefix and script |
− | name = mw.language.fetchLanguageName( lang, "en" ); -- get language name so that we can use it to categorize | + | name = cfg.lang_code_remap[lang] or mw.language.fetchLanguageName( lang, "en" ); -- get language name so that we can use it to categorize |
| if is_set (name) then -- is prefix a proper ISO 639-1 language code? | | if is_set (name) then -- is prefix a proper ISO 639-1 language code? |
| 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 |
Line 547: |
Line 559: |
| return script_value; | | return script_value; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ | | --[[--------------------------< S C R I P T _ C O N C A T E N A T E >------------------------------------------ |
Line 587: |
Line 600: |
| | | |
| | | |
− | --[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >-------------------------------------- | + | --[[--------------------------< W I K I S O U R C E _ U R L _ M A K E >---------------------------------------- |
| + | |
| + | makes a wikisource url from wikisource interwiki link. returns the url and appropriate label; nil else. |
| | | |
− | Format the four chapter parameters: |script-chapter=, |chapter=, |trans-chapter=, and |chapter-url= into a single Chapter meta-
| + | str is the value assigned to |chapter= (or aliases) or |title= or |title-link= |
− | parameter (chapter_url_source used for error messages).
| |
| | | |
| ]] | | ]] |
| | | |
− | local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes) | + | local function wikisource_url_make (str) |
| + | local wl_type, D, L; |
| + | local ws_url, ws_label; |
| + | |
| + | wl_type, D, L = is_wikilink (str); -- wl_type is 0 (not a wikilink), 1 (simple wikilink), 2 (complex wikilink) |
| + | |
| + | if 0 == wl_type then -- not a wikilink; might be from |title-link= |
| + | str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace |
| + | if is_set (str) then |
| + | ws_url = table.concat ({ -- build a wikisource url |
| + | 'https://en.wikisource.org/wiki/', -- prefix |
| + | str, -- article title |
| + | }); |
| + | ws_label = str; -- label for the url |
| + | end |
| + | elseif 1 == wl_type then -- simple wikilink: [[Wikisource:ws article]] |
| + | str = D:match ('^[Ww]ikisource:(.+)') or D:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace |
| + | if is_set (str) then |
| + | ws_url = table.concat ({ -- build a wikisource url |
| + | 'https://en.wikisource.org/wiki/', -- prefix |
| + | str, -- article title |
| + | }); |
| + | ws_label = str; -- label for the url |
| + | end |
| + | elseif 2 == wl_type then -- non-so-simple wikilink: [[Wikisource:ws article|displayed text]] ([[L|D]]) |
| + | str = L:match ('^[Ww]ikisource:(.+)') or L:match ('^[Ss]:(.+)'); -- article title from interwiki link with long-form or short-form namespace |
| + | if is_set (str) then |
| + | ws_label = D; -- get ws article name from display portion of interwiki link |
| + | ws_url = table.concat ({ -- build a wikisource url |
| + | 'https://en.wikisource.org/wiki/', -- prefix |
| + | str, -- article title without namespace from link portion of wikilink |
| + | }); |
| + | end |
| + | end |
| + | |
| + | if ws_url then |
| + | ws_url = mw.uri.encode (ws_url, 'WIKI'); -- make a usable url |
| + | ws_url = ws_url:gsub ('%%23', '#'); -- undo percent encoding of anchor |
| + | end |
| + | |
| + | return ws_url, ws_label, L or D; -- return proper url or nil and a label or nil |
| + | end |
| + | |
| + | |
| + | --[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >-------------------------------------- |
| + | |
| + | 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). |
| + | |
| + | ]] |
| + | |
| + | local function format_chapter_title (scriptchapter, chapter, transchapter, chapterurl, chapter_url_source, no_quotes, access) |
| local chapter_error = ''; | | local chapter_error = ''; |
− | | + | |
| + | local ws_url, ws_label, L = wikisource_url_make (chapter); -- make a wikisource url and label from a wikisource interwiki link |
| + | if ws_url then |
| + | ws_label = ws_label:gsub ('_', ''); -- replace underscore separaters with space characters |
| + | chapter = ws_label; |
| + | end |
| + | |
| if not is_set (chapter) then | | if not is_set (chapter) then |
| chapter = ''; -- to be safe for concatenation | | chapter = ''; -- to be safe for concatenation |
| else | | else |
| if false == no_quotes then | | 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 |
Line 607: |
Line 678: |
| | | |
| chapter = script_concatenate (chapter, scriptchapter) -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped | | chapter = script_concatenate (chapter, scriptchapter) -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped |
| + | |
| + | if is_set (chapterurl) then |
| + | chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate |
| + | elseif ws_url then |
| + | chapter = external_link (ws_url, chapter .. ' ', 'ws link in chapter'); -- adds bare_url_missing_title error if appropriate; space char to move icon away from chap text; TODO: better way to do this? |
| + | chapter = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, chapter}); |
| + | end |
| | | |
| if is_set (transchapter) then | | if is_set (transchapter) then |
Line 618: |
Line 696: |
| end | | end |
| | | |
− | if is_set (chapterurl) then
| + | -- if is_set (chapterurl) then |
− | chapter = external_link (chapterurl, chapter, chapter_url_source, nil); -- adds bare_url_missing_title error if appropriate
| + | -- chapter = external_link (chapterurl, chapter, chapter_url_source, access); -- adds bare_url_missing_title error if appropriate |
− | end
| + | -- end |
| | | |
| return chapter .. chapter_error; | | return chapter .. chapter_error; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< H A S _ I N V I S I B L E _ C H A R S >---------------------------------------- | | --[[--------------------------< H A S _ I N V I S I B L E _ C H A R S >---------------------------------------- |
Line 659: |
Line 738: |
| local pattern=cfg.invisible_chars[i][2] -- the pattern used to find it | | local pattern=cfg.invisible_chars[i][2] -- the pattern used to find it |
| position, dummy, capture = mw.ustring.find (v, pattern) -- see if the parameter value contains characters that match the pattern | | position, dummy, capture = mw.ustring.find (v, pattern) -- see if the parameter value contains characters that match the pattern |
| + | |
| + | if position and (char == 'zero width joiner') then -- if we found a zero width joiner character |
| + | if mw.ustring.find (v, cfg.indic_script) then -- its ok if one of the indic scripts |
| + | position = nil; -- unset position |
| + | end |
| + | end |
| | | |
| if position then | | if position then |
− | if 'nowiki' == capture or 'math' == capture then -- nowiki, math stripmarker (not an error condition) | + | if 'nowiki' == capture or 'math' == capture or -- nowiki and math stripmarkers (not an error condition) |
− | stripmarker = true; -- set a flag | + | ('templatestyles' == capture and in_array (param, {'id', 'quote'})) then -- templatestyles stripmarker allowed in these parameters |
| + | stripmarker = true; -- set a flag |
| elseif true == stripmarker and 'delete' == char then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker | | elseif true == stripmarker and 'delete' == char then -- because stripmakers begin and end with the delete char, assume that we've found one end of a stripmarker |
| position = nil; -- unset | | position = nil; -- unset |
Line 731: |
Line 817: |
| end | | end |
| | | |
− | --[[--------------------------< V A L I D A T E >--------------------------------------------------------------
| |
| | | |
− | Looks for a parameter's name in one of several whitelists.
| + | --[[--------------------------< N O W R A P _ D A T E >-------------------------------------------------------- |
| + | |
| + | When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is |
| + | MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY |
| + | |
| + | DOES NOT yet support MMMM YYYY or any of the date ranges. |
| | | |
− | Parameters in the whitelist can have three values:
| |
− | true - active, supported parameters
| |
− | false - deprecated, supported parameters
| |
− | nil - unsupported parameters
| |
− |
| |
| ]] | | ]] |
| | | |
− | --local function validate( name )
| + | local function nowrap_date (date) |
− | local function validate( name, cite_class ) | + | local cap=''; |
− | local name = tostring( name ); | + | local cap2=''; |
− | local state; | + | |
| + | if date:match("^%d%d%d%d%-%d%d%-%d%d$") then |
| + | 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}); |
| + | end |
| | | |
− | if in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates | + | return date; |
− | state = whitelist.limited_basic_arguments[ name ];
| + | end |
− | if true == state then return true; end -- valid actively supported parameter
| + | |
− | if false == state then
| + | |
− | deprecated_parameter (name); -- parameter is deprecated but still supported
| + | --[[--------------------------< S E T _ T I T L E T Y P E >---------------------------------------------------- |
− | return true;
| |
− | end
| |
| | | |
− | if 'arxiv' == cite_class then -- basic parameters unique to these templates
| + | This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults. |
− | state = whitelist.arxiv_basic_arguments[name];
| + | Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none). |
− | end
| |
− | if 'biorxiv' == cite_class then
| |
− | state = whitelist.biorxiv_basic_arguments[name];
| |
− | end
| |
− | if 'citeseerx' == cite_class then
| |
− | state = whitelist.citeseerx_basic_arguments[name];
| |
− | end
| |
| | | |
− | if true == state then return true; end -- valid actively supported parameter
| + | ]] |
− | if false == state then | + | |
− | deprecated_parameter (name); -- parameter is deprecated but still supported | + | local function set_titletype (cite_class, title_type) |
− | return true;
| + | if is_set(title_type) then |
| + | if "none" == title_type then |
| + | title_type = ""; -- if |type=none then type parameter not displayed |
| end | | end |
− | -- limited enumerated parameters list
| + | return title_type; -- if |type= has been set to any other value use that value |
− | name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last#)
| |
− | state = whitelist.limited_numbered_arguments[ name ];
| |
− | if true == state then return true; end -- valid actively supported parameter | |
− | if false == state then
| |
− | deprecated_parameter (name); -- parameter is deprecated but still supported
| |
− | return true;
| |
− | end
| |
− | | |
− | return false; -- not supported because not found or name is set to nil
| |
− | end -- end limited parameter-set templates
| |
− |
| |
− | state = whitelist.basic_arguments[ name ]; -- all other templates; all normal parameters allowed
| |
− |
| |
− | if true == state then return true; end -- valid actively supported parameter
| |
− | if false == state then
| |
− | deprecated_parameter (name); -- parameter is deprecated but still supported
| |
− | return true;
| |
| end | | end |
− | -- all enumerated parameters allowed
| |
− | name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last#
| |
− | state = whitelist.numbered_arguments[ name ];
| |
| | | |
− | if true == state then return true; end -- valid actively supported parameter | + | return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation |
− | if false == state then
| |
− | deprecated_parameter (name); -- parameter is deprecated but still supported
| |
− | return true;
| |
− | end
| |
− |
| |
− | return false; -- not supported because not found or name is set to nil
| |
| end | | end |
| | | |
| | | |
− | --[[--------------------------< N O W R A P _ D A T E >-------------------------------------------------------- | + | --[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- |
| + | |
| + | Converts a hyphen to a dash under certain conditions. The hyphen must separate like items; unlike items are |
| + | returned unmodified. These forms are modified: |
| + | letter - letter (A - B) |
| + | digit - digit (4-5) |
| + | digit separator digit - digit separator digit (4.1-4.5 or 4-1-4-5) |
| + | letterdigit - letterdigit (A1-A5) (an optional separator between letter and digit is supported – a.1-a.5 or a-1-a-5) |
| + | digitletter - digitletter (5a - 5d) (an optional separator between letter and digit is supported – 5.a-5.d or 5-a-5-d) |
| | | |
− | When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>. When date is DD MMMM YYYY or is
| + | any other forms are returned unmodified. |
− | MMMM DD, YYYY then wrap in nowrap span: <span ...>DD MMMM</span> YYYY or <span ...>MMMM DD,</span> YYYY
| |
| | | |
− | DOES NOT yet support MMMM YYYY or any of the date ranges.
| + | str may be a comma- or semicolon-separated list |
| | | |
| ]] | | ]] |
| | | |
− | local function nowrap_date (date) | + | local function hyphen_to_dash( str ) |
− | local cap='';
| + | if not is_set (str) then |
− | local cap2='';
| + | return str; |
− | | + | end |
− | if date:match("^%d%d%d%d%-%d%d%-%d%d$") then | |
− | 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 | + | str, count = str:gsub ('^%(%((.+)%)%)$', '%1'); -- remove accept-this-as-written markup when it wraps all of str |
− | cap, cap2 = string.match (date, "^(.*)%s+(%d%d%d%d)$");
| + | if 0 ~= count then -- non-zero when markup removed; zero else |
− | date = substitute (cfg.presentation['nowrap2'], {cap, cap2}); | + | return str; -- nothing to do, we're done |
| end | | end |
| | | |
− | return date; | + | str = str:gsub ('&[nm]dash;', {['–'] = '–', ['—'] = '—'}); -- replace — and – entities with their characters; semicolon mucks up the text.split |
− | end
| + | |
| + | local out = {}; |
| + | local list = mw.text.split (str, '%s*[,;]%s*'); -- split str at comma or semicolon separators if there are any |
| | | |
− | --[[--------------------------< S E T _ T I T L E T Y P E >---------------------------------------------------- | + | for _, item in ipairs (list) do -- for each item in the list |
− | | + | if mw.ustring.match (item, '^%w*[%.%-]?%w+%s*[%-–—]%s*%w*[%.%-]?%w+$') then -- if a hyphenated range or has endash or emdash separators |
− | This function sets default title types (equivalent to the citation including |type=<default value>) for those templates that have defaults.
| + | if item:match ('%a+[%.%-]?%d+%s*%-%s*%a+[%.%-]?%d+') or -- letterdigit hyphen letterdigit (optional separator between letter and digit) |
− | Also handles the special case where it is desirable to omit the title type from the rendered citation (|type=none).
| + | item:match ('%d+[%.%-]?%a+%s*%-%s*%d+[%.%-]?%a+') or -- digitletter hyphen digitletter (optional separator between digit and letter) |
− | | + | item:match ('%d+[%.%-]%d+%s*%-%s*%d+[%.%-]%d+') or -- digit separator digit hyphen digit separator digit |
− | ]] | + | item:match ('%d+%s*%-%s*%d+') or -- digit hyphen digit |
− | | + | item:match ('%a+%s*%-%s*%a+') then -- letter hyphen letter |
− | local function set_titletype (cite_class, title_type)
| + | item = item:gsub ('(%w*[%.%-]?%w+)%s*%-%s*(%w*[%.%-]?%w+)', '%1–%2'); -- replace hyphen, remove extraneous space characters |
− | if is_set(title_type) then
| + | else |
− | if "none" == title_type then
| + | item = mw.ustring.gsub (item, '%s*[–—]%s*', '–'); -- for endash or emdash separated ranges, replace em with en, remove extraneous white space |
− | title_type = ""; -- if |type=none then type parameter not displayed | + | end |
| end | | end |
− | return title_type; -- if |type= has been set to any other value use that value | + | item = item:gsub ('^%(%((.+)%)%)$', '%1'); -- remove the accept-this-as-written markup |
| + | table.insert (out, item); -- add the (possibly modified) item to the output table |
| end | | end |
| | | |
− | return cfg.title_types [cite_class] or ''; -- set template's default title type; else empty string for concatenation | + | return table.concat (out, ', '); -- concatenate the output table into a comma separated string |
| end | | end |
| | | |
| | | |
− | --[[--------------------------< H Y P H E N _ T O _ D A S H >-------------------------------------------------- | + | --[[--------------------------< S A F E _ J O I N >------------------------------------------------------------ |
| | | |
− | Converts a hyphen to a dash
| + | Joins a sequence of strings together while checking for duplicate separation characters. |
| | | |
| ]] | | ]] |
| | | |
− | local function hyphen_to_dash( str ) | + | local function safe_join( tbl, duplicate_char ) |
− | if not is_set(str) or str:match( "[%[%]{}<>]" ) ~= nil then | + | local f = {}; -- create a function table appropriate to type of 'dupicate character' |
− | return str; | + | if 1 == #duplicate_char then -- for single byte ascii characters use the string library functions |
− | end
| + | f.gsub=string.gsub |
− | return str:gsub( '-', '–' );
| + | f.match=string.match |
− | end | + | f.sub=string.sub |
| + | else -- for multi-byte characters use the ustring library functions |
| + | f.gsub=mw.ustring.gsub |
| + | f.match=mw.ustring.match |
| + | f.sub=mw.ustring.sub |
| + | end |
| | | |
− | | + | local str = ''; -- the output string |
− | --[[--------------------------< S A F E _ J O I N >------------------------------------------------------------
| |
− | | |
− | Joins a sequence of strings together while checking for duplicate separation characters.
| |
− | | |
− | ]]
| |
− | | |
− | local function safe_join( tbl, duplicate_char )
| |
− | --[[
| |
− | Note: we use string functions here, rather than ustring functions.
| |
− |
| |
− | This has considerably faster performance and should work correctly as
| |
− | long as the duplicate_char is strict ASCII. The strings
| |
− | in tbl may be ASCII or UTF8.
| |
− | ]]
| |
− |
| |
− | local str = ''; -- the output string | |
| local comp = ''; -- what does 'comp' mean? | | local comp = ''; -- what does 'comp' mean? |
| local end_chr = ''; | | local end_chr = ''; |
Line 891: |
Line 947: |
| end | | end |
| -- typically duplicate_char is sepc | | -- typically duplicate_char is sepc |
− | if comp:sub(1,1) == duplicate_char then -- is first charactier same as duplicate_char? why test first character? | + | if f.sub(comp, 1,1) == duplicate_char then -- is first character same as duplicate_char? why test first character? |
− | -- Because individual string segments often (always?) begin with terminal punct for th | + | -- Because individual string segments often (always?) begin with terminal punct for the |
| -- preceding segment: 'First element' .. 'sepc next element' .. etc? | | -- preceding segment: 'First element' .. 'sepc next element' .. etc? |
| trim = false; | | trim = false; |
− | end_chr = str:sub(-1,-1); -- get the last character of the output string | + | end_chr = f.sub(str, -1,-1); -- get the last character of the output string |
| -- str = str .. "<HERE(enchr=" .. end_chr.. ")" -- debug stuff? | | -- str = str .. "<HERE(enchr=" .. end_chr.. ")" -- debug stuff? |
| if end_chr == duplicate_char then -- if same as separator | | if end_chr == duplicate_char then -- if same as separator |
− | str = str:sub(1,-2); -- remove it | + | str = f.sub(str, 1,-2); -- remove it |
| elseif end_chr == "'" then -- if it might be wikimarkup | | elseif end_chr == "'" then -- if it might be wikimarkup |
− | if str:sub(-3,-1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' | + | if f.sub(str, -3,-1) == duplicate_char .. "''" then -- if last three chars of str are sepc'' |
− | str = str:sub(1, -4) .. "''"; -- remove them and add back '' | + | str = f.sub(str, 1, -4) .. "''"; -- remove them and add back '' |
− | elseif str:sub(-5,-1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' | + | elseif f.sub(str, -5,-1) == duplicate_char .. "]]''" then -- if last five chars of str are sepc]]'' |
| trim = true; -- why? why do this and next differently from previous? | | trim = true; -- why? why do this and next differently from previous? |
− | elseif str:sub(-4,-1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' | + | elseif f.sub(str, -4,-1) == duplicate_char .. "]''" then -- if last four chars of str are sepc]'' |
| trim = true; -- same question | | trim = true; -- same question |
| end | | end |
| elseif end_chr == "]" then -- if it might be wikimarkup | | elseif end_chr == "]" then -- if it might be wikimarkup |
− | if str:sub(-3,-1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink | + | if f.sub(str, -3,-1) == duplicate_char .. "]]" then -- if last three chars of str are sepc]] wikilink |
| trim = true; | | trim = true; |
− | elseif str:sub(-2,-1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link | + | elseif f.sub(str, -3,-1) == duplicate_char .. '"]' then -- if last three chars of str are sepc"] quoted external link |
| trim = true; | | trim = true; |
− | elseif str:sub(-4,-1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. | + | elseif f.sub(str, -2,-1) == duplicate_char .. "]" then -- if last two chars of str are sepc] external link |
| + | trim = true; |
| + | elseif f.sub(str, -4,-1) == duplicate_char .. "'']" then -- normal case when |url=something & |title=Title. |
| trim = true; | | trim = true; |
| end | | end |
| elseif end_chr == " " then -- if last char of output string is a space | | elseif end_chr == " " then -- if last char of output string is a space |
− | if str:sub(-2,-1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> | + | if f.sub(str, -2,-1) == duplicate_char .. " " then -- if last two chars of str are <sepc><space> |
− | str = str:sub(1,-3); -- remove them both | + | str = f.sub(str, 1,-3); -- remove them both |
| end | | end |
| end | | end |
Line 924: |
Line 982: |
| if value ~= comp then -- value does not equal comp when value contains html markup | | if value ~= comp then -- value does not equal comp when value contains html markup |
| local dup2 = duplicate_char; | | local dup2 = duplicate_char; |
− | if dup2:match( "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it | + | if f.match(dup2, "%A" ) then dup2 = "%" .. dup2; end -- if duplicate_char not a letter then escape it |
| | | |
− | value = value:gsub( "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows html markup | + | value = f.gsub(value, "(%b<>)" .. dup2, "%1", 1 ) -- remove duplicate_char if it follows html markup |
| else | | else |
− | value = value:sub( 2, -1 ); -- remove duplicate_char when it is first character | + | value = f.sub(value, 2, -1 ); -- remove duplicate_char when it is first character |
| end | | end |
| end | | end |
Line 936: |
Line 994: |
| end | | end |
| return str; | | return str; |
− | end | + | end |
| | | |
| | | |
Line 951: |
Line 1,009: |
| return false; | | return false; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< I S _ G O O D _ V A N C _ N A M E >-------------------------------------------- | | --[[--------------------------< I S _ G O O D _ V A N C _ N A M E >-------------------------------------------- |
Line 997: |
Line 1,056: |
| return true; | | return true; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ | | --[[--------------------------< R E D U C E _ T O _ I N I T I A L S >------------------------------------------ |
Line 1,055: |
Line 1,115: |
| return table.concat(initials) -- Vancouver format does not include spaces. | | return table.concat(initials) -- Vancouver format does not include spaces. |
| end | | end |
| + | |
| | | |
| --[[--------------------------< L I S T _ P E O P L E >------------------------------------------------------- | | --[[--------------------------< L I S T _ P E O P L E >------------------------------------------------------- |
Line 1,071: |
Line 1,132: |
| | | |
| if 'vanc' == format then -- Vancouver-like author/editor name styling? | | if 'vanc' == format then -- Vancouver-like author/editor name styling? |
− | sep = ','; -- name-list separator between authors is a comma | + | sep = cfg.presentation['sep_nl_vanc']; -- name-list separator between authors is a comma |
− | namesep = ' '; -- last/first separator is a space | + | namesep = cfg.presentation['sep_name_vanc']; -- last/first separator is a space |
− | elseif 'mla' == control.mode then
| |
− | sep = ','; -- name-list separator between authors is a comma
| |
− | namesep = ', ' -- last/first separator is <comma><space>
| |
| else | | else |
− | sep = ';' -- name-list separator between authors is a semicolon | + | sep = cfg.presentation['sep_nl']; -- name-list separator between authors is a semicolon |
− | namesep = ', ' -- last/first separator is <comma><space> | + | namesep = cfg.presentation['sep_name']; -- last/first separator is <comma><space> |
| end | | end |
| | | |
Line 1,104: |
Line 1,162: |
| local first = person.first | | local first = person.first |
| if is_set(first) then | | if is_set(first) then |
− | if 'mla' == control.mode then | + | if ( "vanc" == format ) then -- if vancouver format |
− | if i == 1 then -- for mla
| + | one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/) |
− | one = one .. namesep .. first; -- first name last, first
| + | if not person.corporate and is_good_vanc_name (one, first) then -- and name is all Latin characters; corporate authors not tested |
− | else -- all other names
| + | first = reduce_to_initials(first) -- attempt to convert first name(s) to initials |
− | one = first .. ' ' .. one; -- first last
| |
− | end
| |
− | else
| |
− | if ( "vanc" == format ) then -- if vancouver format
| |
− | one = one:gsub ('%.', ''); -- remove periods from surnames (http://www.ncbi.nlm.nih.gov/books/NBK7271/box/A35029/)
| |
− | if not person.corporate and is_good_vanc_name (one, first) then -- and name is all Latin characters; corporate authors not tested
| |
− | first = reduce_to_initials(first) -- attempt to convert first name(s) to initials
| |
− | end
| |
| end | | end |
− | one = one .. namesep .. first;
| |
| end | | end |
| + | one = one .. namesep .. first; |
| end | | end |
| if is_set(person.link) and person.link ~= control.page_name then | | if is_set(person.link) and person.link ~= control.page_name then |
− | one = "[[" .. person.link .. "|" .. one .. "]]" -- link author/editor if this page is not the author's/editor's page | + | one = make_wikilink (person.link, one); -- link author/editor if this page is not the author's/editor's page |
| end | | end |
| end | | end |
Line 1,132: |
Line 1,182: |
| if count > 0 then | | if count > 0 then |
| if count > 1 and is_set(lastauthoramp) and not etal then | | if count > 1 and is_set(lastauthoramp) and not etal then |
− | if 'mla' == control.mode then | + | text[#text-2] = " & "; -- replace last separator with ampersand text |
− | text[#text-2] = ", and "; -- replace last separator with ', and ' text
| |
− | else
| |
− | text[#text-2] = " & "; -- replace last separator with ampersand text
| |
− | end
| |
| end | | end |
| text[#text] = nil; -- erase the last separator | | text[#text] = nil; -- erase the last separator |
Line 1,148: |
Line 1,194: |
| return result, count | | return result, count |
| end | | end |
| + | |
| | | |
| --[[--------------------------< A N C H O R _ I D >------------------------------------------------------------ | | --[[--------------------------< A N C H O R _ I D >------------------------------------------------------------ |
Line 1,227: |
Line 1,274: |
| '^[%(%[]?%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%A', -- (editor or (editors: also sq brackets, case insensitive, optional brackets, 's' | | '^[%(%[]?%s*[Ee][Dd][Ii][Tt][Oo][Rr][Ss]?%A', -- (editor or (editors: also sq brackets, case insensitive, optional brackets, 's' |
| '^[%(%[]?%s*[Ee][Dd][Ii][Tt][Ee][Dd]%A', -- (edited: also sq brackets, case insensitive, optional brackets | | '^[%(%[]?%s*[Ee][Dd][Ii][Tt][Ee][Dd]%A', -- (edited: also sq brackets, case insensitive, optional brackets |
− |
| |
| } | | } |
| | | |
Line 1,349: |
Line 1,395: |
| return names, etal; -- all done, return our list of names | | return names, etal; -- all done, return our list of names |
| end | | end |
| + | |
| | | |
| --[[--------------------------< G E T _ I S O 6 3 9 _ C O D E >------------------------------------------------ | | --[[--------------------------< G E T _ I S O 6 3 9 _ C O D E >------------------------------------------------ |
Line 1,359: |
Line 1,406: |
| return the original language name string. | | return the original language name string. |
| | | |
− | mw.language.fetchLanguageNames(<local wiki language>, 'all') return a list of languages that in some cases may include | + | mw.language.fetchLanguageNames(<local wiki language>, 'all') returns a list of languages that in some cases may include |
| extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support | | extensions. For example, code 'cbk-zam' and its associated name 'Chavacano de Zamboanga' (MediaWiki does not support |
− | code 'cbk' or name 'Chavacano'. | + | code 'cbk' or name 'Chavacano'. Most (all?) of these languages are not used a 'language' codes per se, rather they |
| + | are used as sub-domain names: cbk-zam.wikipedia.org. A list of language names and codes supported by fetchLanguageNames() |
| + | can be found at Template:Citation Style documentation/language/doc |
| | | |
− | Names but that are included in the list will be found if that name is provided in the |language= parameter. For example, | + | Names that are included in the list will be found if that name is provided in the |language= parameter. For example, |
| if |language=Chavacano de Zamboanga, that name will be found with the associated code 'cbk-zam'. When names are found | | if |language=Chavacano de Zamboanga, that name will be found with the associated code 'cbk-zam'. When names are found |
− | and the associated code is not two or three characters, this function returns only the Wikimedia language name. | + | and the associated code is not two or three characters, this function returns only the WikiMedia language name. |
| + | |
| + | Some language names have multiple entries under different codes: |
| + | Aromanian has code rup and code roa-rup |
| + | When this occurs, this function returns the language name and the 2- or 3-character code |
| | | |
| Adapted from code taken from Module:Check ISO 639-1. | | Adapted from code taken from Module:Check ISO 639-1. |
Line 1,372: |
Line 1,425: |
| | | |
| local function get_iso639_code (lang, this_wiki_code) | | local function get_iso639_code (lang, this_wiki_code) |
− | if 'bangla' == lang:lower() then -- special case related to Wikimedia remap of code 'bn' at mw:Extension:CLDR | + | if cfg.lang_name_remap[lang:lower()] then -- if there is a remapped name (because MediaWiki uses something that we don't think is correct) |
− | return 'Bengali', 'bn'; -- make sure rendered version is properly capitalized | + | return cfg.lang_name_remap[lang:lower()][1], cfg.lang_name_remap[lang:lower()][2]; -- for this language 'name', return a possibly new name and appropriate code |
| end | | end |
| | | |
| + | local ietf_code; -- because some languages have both ietf-like codes and iso 639-like codes |
| + | local ietf_name; |
| + | |
| local languages = mw.language.fetchLanguageNames(this_wiki_code, 'all') -- get a list of language names known to Wikimedia | | local languages = mw.language.fetchLanguageNames(this_wiki_code, 'all') -- get a list of language names known to Wikimedia |
| -- ('all' is required for North Ndebele, South Ndebele, and Ojibwa) | | -- ('all' is required for North Ndebele, South Ndebele, and Ojibwa) |
| local langlc = mw.ustring.lower(lang); -- lower case version for comparisons | | local langlc = mw.ustring.lower(lang); -- lower case version for comparisons |
− |
| + | |
| for code, name in pairs(languages) do -- scan the list to see if we can find our language | | for code, name in pairs(languages) do -- scan the list to see if we can find our language |
| if langlc == mw.ustring.lower(name) then | | if langlc == mw.ustring.lower(name) then |
− | if 2 ~= code:len() and 3 ~= code:len() then -- two- or three-character codes only; extensions not supported | + | if 2 == code:len() or 3 == code:len() then -- two- or three-character codes only; extensions not supported |
− | return name; -- so return the name but not the code | + | return name, code; -- so return the name and the code |
| end | | end |
− | return name, code; -- found it, return name to ensure proper capitalization and the the code | + | ietf_code = code; -- remember that we found an ietf-like code and save its name |
| + | ietf_name = name; -- but keep looking for a 2- or 3-char code |
| end | | end |
| end | | end |
− | return lang; -- not valid language; return language in original case and nil for the code | + | -- didn't find name with 2- or 3-char code; if ietf-like code found return |
| + | return ietf_code and ietf_name or lang; -- associated name; return original language text else |
| end | | end |
| | | |
Line 1,422: |
Line 1,480: |
| | | |
| for _, lang in ipairs (names_table) do -- reuse lang | | for _, lang in ipairs (names_table) do -- reuse lang |
| + | name = cfg.lang_code_remap[lang:lower()]; -- first see if this is a code that is not supported by MediaWiki but is in remap |
| | | |
− | if lang:match ('^%a%a%-') then -- strip ietf language tags from code; TODO: is there a need to support 3-char with tag? | + | if name then -- there was a remapped code so |
− | lang = lang:match ('(%a%a)%-') -- keep only 639-1 code portion to lang; TODO: do something with 3166 alpha 2 country code?
| + | lang = lang:gsub ('^(%a%a%a?)%-.*', '%1'); -- strip ietf tags from code |
| + | else |
| + | if lang:match ('^%a%a%-') then -- strip ietf tags from code; TODO: is there a need to support 3-char with tag? |
| + | 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() or 3 == lang:len() then -- if two-or three-character code |
| + | name = mw.language.fetchLanguageName (lang:lower(), this_wiki_code); -- get language name if |language= is a proper code |
| + | end |
| end | | end |
− | if 2 == lang:len() or 3 == lang:len() then -- if two-or three-character code
| + | |
− | name = mw.language.fetchLanguageName( lang:lower(), this_wiki_code); -- get language name if |language= is a proper code
| |
− | end
| |
− |
| |
| if is_set (name) then -- if |language= specified a valid code | | if is_set (name) then -- if |language= specified a valid code |
| code = lang:lower(); -- save it | | code = lang:lower(); -- save it |
Line 1,437: |
Line 1,500: |
| | | |
| if is_set (code) then -- only 2- or 3-character codes | | if is_set (code) then -- only 2- or 3-character codes |
− | if 'bn' == code then name = 'Bengali' end; -- override wikimedia when code is 'bn' | + | name = cfg.lang_code_remap[code] or name; -- override wikimedia when they misuse language codes/names |
| + | |
| if this_wiki_code ~= code then -- when the language is not the same as this wiki's language | | if this_wiki_code ~= code then -- when the language is not the same as this wiki's language |
| if 2 == code:len() then -- and is a two-character code | | if 2 == code:len() then -- and is a two-character code |
− | add_prop_cat ('foreign_lang_source', {name, code}) -- categorize it | + | add_prop_cat ('foreign_lang_source' .. code, {name, code}) -- categorize it |
| else -- or is a recognized language (but has a three-character code) | | else -- or is a recognized language (but has a three-character code) |
− | add_prop_cat ('foreign_lang_source_2', {code}) -- categorize it differently TODO: support mutliple three-character code categories per cs1|2 template | + | add_prop_cat ('foreign_lang_source_2' .. code, {code}) -- categorize it differently TODO: support mutliple three-character code categories per cs1|2 template |
| end | | end |
| end | | end |
Line 1,455: |
Line 1,519: |
| code = #language_list -- reuse code as number of languages in the list | | code = #language_list -- reuse code as number of languages in the list |
| if 2 >= code then | | if 2 >= code then |
− | name = table.concat (language_list, ' and ') -- insert '<space>and<space>' between two language names | + | name = table.concat (language_list, cfg.messages['parameter-pair-separator']) -- insert '<space>and<space>' between two language names |
| elseif 2 < code then | | elseif 2 < code then |
− | language_list[code] = 'and ' .. language_list[code]; -- prepend last name with 'and<space>' | + | name = table.concat (language_list, ', '); -- and concatenate with '<comma><space>' separators |
− | name = table.concat (language_list, ', ') -- and concatenate with '<comma><space>' separators | + | name = name:gsub (', ([^,]+)$', cfg.messages['parameter-final-separator'] .. '%1'); -- replace last '<comma><space>' separator with '<comma><space>and<space>' separator |
| end | | end |
| if this_wiki_name == name then | | if this_wiki_name == name then |
Line 1,468: |
Line 1,532: |
| ]] | | ]] |
| end | | end |
| + | |
| | | |
| --[[--------------------------< S E T _ C S 1 _ S T Y L E >---------------------------------------------------- | | --[[--------------------------< S E T _ C S 1 _ S T Y L E >---------------------------------------------------- |
| | | |
| Set style settings for CS1 citation templates. Returns separator and postscript settings | | Set style settings for CS1 citation templates. Returns separator and postscript settings |
| + | At en.wiki, for cs1: |
| + | ps gets: '.' |
| + | sep gets: '.' |
| | | |
| ]] | | ]] |
Line 1,477: |
Line 1,545: |
| local function set_cs1_style (ps) | | local function set_cs1_style (ps) |
| if not is_set (ps) then -- unless explicitely set to something | | if not is_set (ps) then -- unless explicitely set to something |
− | ps = '.'; -- terminate the rendered citation with a period | + | ps = cfg.presentation['ps_cs1']; -- terminate the rendered citation |
| end | | end |
− | return '.', ps; -- separator is a full stop | + | return cfg.presentation['sep_cs1'], ps; -- element separator |
| end | | end |
| + | |
| | | |
| --[[--------------------------< S E T _ C S 2 _ S T Y L E >---------------------------------------------------- | | --[[--------------------------< S E T _ C S 2 _ S T Y L E >---------------------------------------------------- |
| | | |
| Set style settings for CS2 citation templates. Returns separator, postscript, ref settings | | Set style settings for CS2 citation templates. Returns separator, postscript, ref settings |
| + | At en.wiki, for cs2: |
| + | ps gets: '' (empty string - no terminal punctuation) |
| + | sep gets: ',' |
| | | |
| ]] | | ]] |
Line 1,490: |
Line 1,562: |
| local function set_cs2_style (ps, ref) | | local function set_cs2_style (ps, ref) |
| if not is_set (ps) then -- if |postscript= has not been set, set cs2 default | | if not is_set (ps) then -- if |postscript= has not been set, set cs2 default |
− | ps = ''; -- make sure it isn't nil | + | ps = cfg.presentation['ps_cs2']; -- terminate the rendered citation |
| end | | end |
| if not is_set (ref) then -- if |ref= is not set | | if not is_set (ref) then -- if |ref= is not set |
| ref = "harv"; -- set default |ref=harv | | ref = "harv"; -- set default |ref=harv |
| end | | end |
− | return ',', ps, ref; -- separator is a comma | + | return cfg.presentation['sep_cs2'], ps, ref; -- element separator |
| end | | end |
| + | |
| | | |
| --[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >---------------------- | | --[[--------------------------< G E T _ S E T T I N G S _ F R O M _ C I T E _ C L A S S >---------------------- |
Line 1,515: |
Line 1,588: |
| return sep, ps, ref -- return them all | | return sep, ps, ref -- return them all |
| end | | end |
| + | |
| | | |
| --[[--------------------------< S E T _ S T Y L E >------------------------------------------------------------ | | --[[--------------------------< S E T _ S T Y L E >------------------------------------------------------------ |
Line 1,528: |
Line 1,602: |
| sep, ps, ref = set_cs2_style (ps, ref); | | sep, ps, ref = set_cs2_style (ps, ref); |
| elseif 'cs1' == mode then -- if this template is to be rendered in CS1 (cite xxx) style | | elseif 'cs1' == mode then -- if this template is to be rendered in CS1 (cite xxx) style |
− | sep, ps = set_cs1_style (ps);
| |
− | elseif 'mla' == mode then -- if this template is to be rendered in mla style use cs1 for bot cs1 & cs2 templates
| |
| sep, ps = set_cs1_style (ps); | | sep, ps = set_cs1_style (ps); |
| else -- anything but cs1 or cs2 | | else -- anything but cs1 or cs2 |
Line 1,540: |
Line 1,612: |
| return sep, ps, ref | | return sep, ps, ref |
| end | | end |
| + | |
| | | |
| --[=[-------------------------< I S _ P D F >------------------------------------------------------------------ | | --[=[-------------------------< I S _ P D F >------------------------------------------------------------------ |
Line 1,546: |
Line 1,619: |
| applying the pdf icon to external links. | | applying the pdf icon to external links. |
| | | |
− | returns true if file extension is one of the recognized extension, else false | + | returns true if file extension is one of the recognized extensions, else false |
| | | |
| ]=] | | ]=] |
| | | |
| local function is_pdf (url) | | local function is_pdf (url) |
− | return url:match ('%.pdf[%?#]?') or url:match ('%.PDF[%?#]?'); | + | return url:match ('%.pdf$') or url:match ('%.PDF$') or url:match ('%.pdf[%?#]') or url:match ('%.PDF[%?#]'); |
| end | | end |
| + | |
| | | |
| --[[--------------------------< S T Y L E _ F O R M A T >------------------------------------------------------ | | --[[--------------------------< S T Y L E _ F O R M A T >------------------------------------------------------ |
Line 1,565: |
Line 1,639: |
| local function style_format (format, url, fmt_param, url_param) | | local function style_format (format, url, fmt_param, url_param) |
| if is_set (format) then | | if is_set (format) then |
− | format = wrap_style ('format', format); -- add leading space, parenthases, resize | + | format = wrap_style ('format', format); -- add leading space, parentheses, resize |
| if not is_set (url) then | | if not is_set (url) then |
| format = format .. set_error( 'format_missing_url', {fmt_param, url_param} ); -- add an error message | | format = format .. set_error( 'format_missing_url', {fmt_param, url_param} ); -- add an error message |
Line 1,576: |
Line 1,650: |
| return format; | | return format; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< G E T _ D I S P L A Y _ A U T H O R S _ E D I T O R S >------------------------ | | --[[--------------------------< G E T _ D I S P L A Y _ A U T H O R S _ E D I T O R S >------------------------ |
Line 1,618: |
Line 1,693: |
| return max, etal; | | return max, etal; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >------------------------------ | | --[[--------------------------< E X T R A _ T E X T _ I N _ P A G E _ C H E C K >------------------------------ |
Line 1,631: |
Line 1,707: |
| | | |
| local function extra_text_in_page_check (page) | | local function extra_text_in_page_check (page) |
− | -- 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 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]'; | | local bad_pattern = '^[Pp]?[Pp]%.?[ %d]'; |
| | | |
Line 1,639: |
Line 1,713: |
| add_maint_cat ('extra_text'); | | add_maint_cat ('extra_text'); |
| end | | end |
− | -- if Page:match ('^[Pp]?[Pp]%.?[ %d]') or Page:match ('^[Pp]ages?[ %d]') or
| |
− | -- Pages:match ('^[Pp]?[Pp]%.?[ %d]') or Pages:match ('^[Pp]ages?[ %d]') then
| |
− | -- add_maint_cat ('extra_text');
| |
− | -- end
| |
| end | | end |
| | | |
− | --[[--------------------------< G E T _ V _ N A M E _ T A B L E >----------------------------------------------
| |
| | | |
− | split apart a |vautthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled | + | --[=[-------------------------< G E T _ V _ N A M E _ T A B L E >---------------------------------------------- |
| + | |
| + | split apart a |vauthors= or |veditors= parameter. This function allows for corporate names, wrapped in doubled |
| parentheses to also have commas; in the old version of the code, the doubled parnetheses were included in the | | parentheses to also have commas; in the old version of the code, the doubled parnetheses were included in the |
− | rendered citation and in the metadata. | + | rendered citation and in the metadata. Individual author names may be wikilinked |
| | | |
− | |vauthors=Jones AB, White EB, ((Black, Brown, and Co.)) | + | |vauthors=Jones AB, [[E. B. White|White EB]], ((Black, Brown, and Co.)) |
| | | |
− | This code is experimental and may not be retained.
| + | ]=] |
| | | |
− | ]]
| + | local function get_v_name_table (vparam, output_table, output_link_table) |
− | local function get_v_name_table (vparam, output_table) | |
| local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas | | local name_table = mw.text.split(vparam, "%s*,%s*"); -- names are separated by commas |
| + | local wl_type, label, link; -- wl_type not used here; just a place holder |
| | | |
| local i = 1; | | local i = 1; |
Line 1,673: |
Line 1,744: |
| end | | end |
| table.insert (output_table, name); -- and add corporate name to the output table | | table.insert (output_table, name); -- and add corporate name to the output table |
| + | table.insert (output_link_table, ''); -- no wikilink |
| else | | else |
− | table.insert (output_table, name_table[i]); -- add this name | + | wl_type, label, link = is_wikilink (name_table[i]); -- wl_type is: 0, no wl (text in label variable); 1, [[D]]; 2, [[L|D]] |
| + | table.insert (output_table, label); -- add this name |
| + | if 1 == wl_type then |
| + | table.insert (output_link_table, label); -- simple wikilink [[D]] |
| + | else |
| + | table.insert (output_link_table, link); -- no wikilink or [[L|D]]; add this link if there is one, else empty string |
| + | end |
| end | | end |
| i = i+1; | | i = i+1; |
Line 1,680: |
Line 1,758: |
| return output_table; | | return output_table; |
| end | | end |
| + | |
| | | |
| --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- | | --[[--------------------------< P A R S E _ V A U T H O R S _ V E D I T O R S >-------------------------------- |
Line 1,699: |
Line 1,778: |
| local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= | | local names = {}; -- table of names assembled from |vauthors=, |author-maskn=, |author-linkn= |
| local v_name_table = {}; | | local v_name_table = {}; |
| + | local v_link_table = {}; -- when name is wikilinked, targets go in this table |
| local etal = false; -- return value set to true when we find some form of et al. vauthors parameter | | local etal = false; -- return value set to true when we find some form of et al. vauthors parameter |
| local last, first, link, mask, suffix; | | local last, first, link, mask, suffix; |
Line 1,704: |
Line 1,784: |
| | | |
| vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) | | vparam, etal = name_has_etal (vparam, etal, true); -- find and remove variations on et al. do not categorize (do it here because et al. might have a period) |
− | if vparam:find ('%[%[') or vparam:find ('%]%]') then -- no wikilinking vauthors names
| + | v_name_table = get_v_name_table (vparam, v_name_table, v_link_table); -- names are separated by commas |
− | add_vanc_error ('wikilink');
| |
− | end
| |
− | v_name_table = get_v_name_table (vparam, v_name_table); -- names are separated by commas | |
| | | |
| for i, v_name in ipairs(v_name_table) do | | for i, v_name in ipairs(v_name_table) do |
Line 1,751: |
Line 1,828: |
| end | | end |
| end | | end |
− | -- this from extract_names ()
| + | |
− | link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ); | + | link = select_one( args, cfg.aliases[list_name .. '-Link'], 'redundant_parameters', i ) or v_link_table[i]; |
| mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ); | | mask = select_one( args, cfg.aliases[list_name .. '-Mask'], 'redundant_parameters', i ); |
| names[i] = {last = last, first = first, link = link, mask = mask, corporate=corporate}; -- add this assembled name to our names list | | names[i] = {last = last, first = first, link = link, mask = mask, corporate=corporate}; -- add this assembled name to our names list |
Line 1,811: |
Line 1,888: |
| This function is used to validate a parameter's assigned value for those parameters that have only a limited number | | 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 | | 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 | + | in the source template) the function returns true. If the parameter value is one of the list of allowed values returns |
| true; else, emits an error message and returns false. | | true; else, emits an error message and returns false. |
| | | |
| ]] | | ]] |
| | | |
− | local function is_valid_parameter_value (value, name, possible, cite_class) | + | local function is_valid_parameter_value (value, name, possible) |
− | -- begin hack to limit |mode=mla to a specific set of templates
| |
− | if ('mode' == name) and ('mla' == value) and not in_array (cite_class, {'book', 'journal', 'news'}) then
| |
− | 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 hack
| |
− | | |
| if not is_set (value) then | | if not is_set (value) then |
| return true; -- an empty parameter is ok | | return true; -- an empty parameter is ok |
Line 1,862: |
Line 1,932: |
| ]] | | ]] |
| | | |
− | local function format_volume_issue (volume, issue, cite_class, origin, sepc, lower, mode) | + | local function format_volume_issue (volume, issue, cite_class, origin, sepc, lower) |
| if not is_set (volume) and not is_set (issue) then | | if not is_set (volume) and not is_set (issue) then |
| return ''; | | return ''; |
| end | | end |
| | | |
− | if ('mla' == mode) and ('journal' == cite_class) then -- same as cs1 for magazines
| |
− | lower = true; -- mla 8th edition; force these to lower case
| |
− | 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 '';
| |
− | end
| |
− | end
| |
− |
| |
| if 'magazine' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then | | if 'magazine' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'magazine' == origin) then |
| if is_set (volume) and is_set (issue) then | | if is_set (volume) and is_set (issue) then |
Line 1,888: |
Line 1,947: |
| end | | end |
| | | |
− | local vol = ''; | + | local vol = ''; -- here for all cites except magazine |
| | | |
| if is_set (volume) then | | if is_set (volume) then |
− | if (4 < mw.ustring.len(volume)) then | + | if volume:match ('^[MDCLXVI]+$') or volume:match ('^%d+$')then -- volume value is all digits or all uppercase roman numerals |
− | vol = substitute (cfg.messages['j-vol'], {sepc, volume}); | + | vol = substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); -- render in bold face |
− | else | + | elseif (4 < mw.ustring.len(volume)) then -- not all digits or roman numerals and longer than 4 characters |
− | vol = substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); | + | vol = substitute (cfg.messages['j-vol'], {sepc, volume}); -- not bold |
| + | add_prop_cat ('long_vol'); |
| + | else -- four or less characters |
| + | vol = substitute (cfg.presentation['vol-bold'], {sepc, hyphen_to_dash(volume)}); -- bold |
| end | | end |
| end | | end |
Line 1,904: |
Line 1,966: |
| | | |
| | | |
− | --[[-------------------------< N O R M A L I Z E _ P A G E _ L I S T >----------------------------------------- | + | --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >----------------------------------------- |
| | | |
− | not currently used
| + | adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings. |
| + | The return order is: |
| + | page, pages, sheet, sheets |
| | | |
− | normalizes a comma, ampersand, and/or space separated list to be '<value>, <value>, ..., <value>'
| + | Singular has priority over plural when both are provided. |
− | returns list unchanged if there are no commas else strips whitespace and then reformats the list
| |
| | | |
− | ]]
| |
− | --[[
| |
− | local function normalize_page_list (list)
| |
− | if not list:find ('[,& ]') then return list end -- if list is not delimited with commas, ampersands, or spaces; done
| |
− |
| |
− | list = mw.text.split (list, '[,&%s]+'); -- make a table of values
| |
− | list = table.concat (list, ', '); -- and now make a normalized list
| |
− | return list;
| |
− | end
| |
| ]] | | ]] |
| | | |
− | | + | local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower) |
− | --[[-------------------------< F O R M A T _ P A G E S _ S H E E T S >-----------------------------------------
| |
− | | |
− | adds static text to one of |page(s)= or |sheet(s)= values and returns it with all of the others set to empty strings.
| |
− | The return order is:
| |
− | page, pages, sheet, sheets
| |
− | | |
− | Singular has priority over plural when both are provided.
| |
− | | |
− | ]]
| |
− | | |
− | local function format_pages_sheets (page, pages, sheet, sheets, cite_class, origin, sepc, nopp, lower, mode) | |
| if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators | | if 'map' == cite_class then -- only cite map supports sheet(s) as in-source locators |
| if is_set (sheet) then | | if is_set (sheet) then |
Line 1,950: |
Line 1,993: |
| end | | end |
| | | |
− | local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map'}) and 'journal' == origin); | + | local is_journal = 'journal' == cite_class or (in_array (cite_class, {'citation', 'map', 'interview'}) and 'journal' == origin); |
| | | |
− | if is_journal and 'mla' == mode then
| |
− | is_journal = false; -- mla always uses p & pp
| |
− | end
| |
− |
| |
| if is_set (page) then | | if is_set (page) then |
| if is_journal then | | if is_journal then |
Line 1,978: |
Line 2,017: |
| return '', '', '', ''; -- return empty strings | | return '', '', '', ''; -- return empty strings |
| end | | end |
| + | |
| + | |
| + | --[[--------------------------< I N S O U R C E _ L O C _ G E T >---------------------------------------------- |
| + | |
| + | returns one of the in-source locators: page, pages, or at. |
| + | |
| + | If any of these are interwiki links to wikisource, returns the label portion of the interwikilink as plain text |
| + | for use in COinS. This COinS thing is done because here we convert an interwiki link to and external link and |
| + | add an icon span around that; get_coins_pages() doesn't know about the span. TODO: should it? |
| + | |
| + | TODO: add support for sheet and sheets?; streamline; |
| + | |
| + | TODO: make it so that this function returns only one of the three as the single in-source (the return value assigned |
| + | to a new name)? |
| + | |
| + | ]] |
| + | |
| + | local function insource_loc_get (page, pages, at) |
| + | local ws_url, ws_label, coins_pages, L; -- for wikisource interwikilinks; TODO: this corrupts page metadata (span remains in place after cleanup; fix there?) |
| + | |
| + | if is_set (page) then |
| + | if is_set (pages) or is_set(at) then |
| + | pages = ''; -- unset the others |
| + | at = ''; |
| + | end |
| + | extra_text_in_page_check (page); -- add this page to maint cat if |page= value begins with what looks like p. or pp. |
| + | |
| + | ws_url, ws_label, L = wikisource_url_make (page); -- make ws url from |page= interwiki link; link portion L becomes tool tip label |
| + | if ws_url then |
| + | page = external_link (ws_url, ws_label .. ' ', 'ws link in page'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? |
| + | page = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, page}); |
| + | coins_pages = ws_label; |
| + | end |
| + | elseif is_set (pages) then |
| + | if is_set (at) then |
| + | at = ''; -- unset |
| + | end |
| + | extra_text_in_page_check (pages); -- add this page to maint cat if |pages= value begins with what looks like p. or pp. |
| + | |
| + | ws_url, ws_label, L = wikisource_url_make (pages); -- make ws url from |pages= interwiki link; link portion L becomes tool tip label |
| + | if ws_url then |
| + | pages = external_link (ws_url, ws_label .. ' ', 'ws link in pages'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? |
| + | pages = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, pages}); |
| + | coins_pages = ws_label; |
| + | end |
| + | elseif is_set (at) then |
| + | ws_url, ws_label, L = wikisource_url_make (at); -- make ws url from |at= interwiki link; link portion L becomes tool tip label |
| + | if ws_url then |
| + | at = external_link (ws_url, ws_label .. ' ', 'ws link in at'); -- space char after label to move icon away from in-source text; TODO: a better way to do this? |
| + | at = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, at}); |
| + | coins_pages = ws_label; |
| + | end |
| + | end |
| + | |
| + | return page, pages, at, coins_pages; |
| + | end |
| + | |
| | | |
| | | |
Line 2,054: |
Line 2,150: |
| | | |
| | | |
− | --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ | + | --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------ |
| | | |
− | Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal
| + | This is the main function doing the majority of the citation formatting. |
− | sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a
| |
− | parameter that is missing its pipe:
| |
− | {{cite ... |title=Title access-date=2016-03-17}}
| |
− | | |
− | cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html
| |
− | tags are removed before the search.
| |
− | | |
− | If a missing pipe is detected, this function adds the missing pipe maintenance category.
| |
− | | |
− | ]]
| |
− | | |
− | local function missing_pipe_check (value)
| |
− | local capture;
| |
− | value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc
| |
− | | |
− | capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes
| |
− | if capture and validate (capture) then -- if the capture is a valid parameter name
| |
− | add_maint_cat ('missing_pipe');
| |
− | end
| |
− | end
| |
− | | |
− | | |
− | --[[--------------------------< C I T A T I O N 0 >------------------------------------------------------------
| |
− | | |
− | This is the main function doing the majority of the citation formatting. | |
| | | |
| ]] | | ]] |
Line 2,096: |
Line 2,167: |
| -- define different field names for the same underlying things. | | -- define different field names for the same underlying things. |
| | | |
− | -- 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. |
| local Mode = A['Mode']; | | local Mode = A['Mode']; |
− | if not is_valid_parameter_value (Mode, 'mode', cfg.keywords['mode'], config.CitationClass) then | + | if not is_valid_parameter_value (Mode, 'mode', cfg.keywords['mode']) then |
| Mode = ''; | | Mode = ''; |
| end | | end |
Line 2,148: |
Line 2,219: |
| local Translators; -- assembled translators name list | | local Translators; -- assembled translators name list |
| t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= | | t = extract_names (args, 'TranslatorList'); -- fetch translator list from |translatorn= / |translator-lastn=, -firstn=, -linkn=, -maskn= |
− |
| |
| | | |
− | local interviewers_list = {}; | + | local interviewers_list = {}; |
− | local Interviewers = A['Interviewers'] | + | local Interviewers; -- used later |
− | if is_set (Interviewers) then -- add a maint cat if the |interviewers= is used
| + | interviewers_list = extract_names (args, 'InterviewerList'); -- process preferred interviewers parameters |
− | add_maint_cat ('interviewers'); -- because use of this parameter is discouraged
| |
− | else | |
− | interviewers_list = extract_names (args, 'InterviewerList'); -- else, process preferred interviewers parameters
| |
− | end
| |
| | | |
| local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs | | local c = {}; -- contributors list from |contributor-lastn= / contributor-firstn= pairs |
Line 2,236: |
Line 2,302: |
| local Pages; | | local Pages; |
| local At; | | local At; |
− | -- previously conference books did not support volume
| + | |
− | -- if in_array (config.CitationClass, cfg.templates_using_volume) and not ('conference' == config.CitationClass and not is_set (Periodical)) then
| |
| if in_array (config.CitationClass, cfg.templates_using_volume) then | | if in_array (config.CitationClass, cfg.templates_using_volume) then |
| Volume = A['Volume']; | | Volume = A['Volume']; |
Line 2,243: |
Line 2,308: |
| -- conference & map books do not support issue | | -- conference & map books do not support issue |
| if in_array (config.CitationClass, cfg.templates_using_issue) and not (in_array (config.CitationClass, {'conference', 'map'}) and not is_set (Periodical))then | | 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']; | + | Issue = hyphen_to_dash (A['Issue']); |
| end | | end |
| local Position = ''; | | local Position = ''; |
| if not in_array (config.CitationClass, cfg.templates_not_using_page) then | | if not in_array (config.CitationClass, cfg.templates_not_using_page) then |
| Page = A['Page']; | | Page = A['Page']; |
− | Pages = hyphen_to_dash( A['Pages'] ); | + | Pages = hyphen_to_dash (A['Pages']); |
| At = A['At']; | | At = A['At']; |
| end | | end |
Line 2,261: |
Line 2,326: |
| RegistrationRequired=nil; | | RegistrationRequired=nil; |
| end | | end |
| + | |
| local SubscriptionRequired = A['SubscriptionRequired']; | | local SubscriptionRequired = A['SubscriptionRequired']; |
| if not is_valid_parameter_value (SubscriptionRequired, 'subscription', cfg.keywords ['yes_true_y']) then | | if not is_valid_parameter_value (SubscriptionRequired, 'subscription', cfg.keywords ['yes_true_y']) then |
| SubscriptionRequired=nil; | | SubscriptionRequired=nil; |
| end | | end |
| + | |
| local UrlAccess = A['UrlAccess']; | | local UrlAccess = A['UrlAccess']; |
| if not is_valid_parameter_value (UrlAccess, 'url-access', cfg.keywords ['url-access']) then | | if not is_valid_parameter_value (UrlAccess, 'url-access', cfg.keywords ['url-access']) then |
Line 2,283: |
Line 2,350: |
| end | | end |
| | | |
| + | local ChapterUrlAccess = A['ChapterUrlAccess']; |
| + | if not is_valid_parameter_value (ChapterUrlAccess, 'chapter-url-access', cfg.keywords ['url-access']) then -- same as url-access |
| + | ChapterUrlAccess = nil; |
| + | end |
| + | if not is_set(ChapterURL) and is_set(ChapterUrlAccess) then |
| + | ChapterUrlAccess = nil; |
| + | table.insert( z.message_tail, { set_error( 'param_access_requires_param', {'chapter-url'}, true ) } ); |
| + | end |
| | | |
| local Via = A['Via']; | | local Via = A['Via']; |
Line 2,318: |
Line 2,393: |
| LastAuthorAmp = nil; -- set to empty string | | LastAuthorAmp = nil; -- set to empty string |
| end | | end |
− | if 'mla' == Mode then
| + | |
− | LastAuthorAmp = 'yes'; -- replaces last author/editor separator with ' and ' text
| |
− | 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 | | if not is_valid_parameter_value (no_tracking_cats, 'no-tracking', cfg.keywords ['yes_true_y']) then |
Line 2,326: |
Line 2,399: |
| end | | end |
| | | |
− | --local variables that are not cs1 parameters | + | --local variables that are not cs1 parameters |
| local use_lowercase; -- controls capitalization of certain static text | | local use_lowercase; -- controls capitalization of certain static text |
| local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language | | local this_page = mw.title.getCurrentTitle(); -- also used for COinS and for language |
Line 2,343: |
Line 2,416: |
| use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text | | use_lowercase = ( sepc == ',' ); -- used to control capitalization for certain static text |
| | | |
− | --check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories | + | --check this page to see if it is in one of the namespaces that cs1 is not supposed to add to the error categories |
| if not is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page | | if not is_set (no_tracking_cats) then -- ignore if we are already not going to categorize this page |
| if in_array (this_page.nsText, cfg.uncategorized_namespaces) then | | if in_array (this_page.nsText, cfg.uncategorized_namespaces) then |
Line 2,356: |
Line 2,429: |
| end | | end |
| | | |
− | -- check for extra |page=, |pages= or |at= parameters. (also sheet and sheets while we're at it) | + | -- 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 | | 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 coins_pages; |
| + | |
| + | Page, Pages, At, coins_pages = insource_loc_get (Page, Pages, At); |
| | | |
| local NoPP = A['NoPP'] | | local NoPP = A['NoPP'] |
Line 2,366: |
Line 2,443: |
| end | | end |
| | | |
− | if is_set(Page) then | + | -- both |publication-place= and |place= (|location=) allowed if different |
− | if is_set(Pages) or is_set(At) then
| |
− | Pages = ''; -- unset the others
| |
− | At = '';
| |
− | end
| |
− | extra_text_in_page_check (Page); -- 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
| |
− | At = ''; -- unset
| |
− | end
| |
− | extra_text_in_page_check (Pages); -- add this page to maint cat if |pages= value begins with what looks like p. or pp.
| |
− | end
| |
− | | |
− | -- both |publication-place= and |place= (|location=) allowed if different | |
| if not is_set(PublicationPlace) and is_set(Place) then | | if not is_set(PublicationPlace) and is_set(Place) then |
| PublicationPlace = Place; -- promote |place= (|location=) to |publication-place | | PublicationPlace = Place; -- promote |place= (|location=) to |publication-place |
Line 2,386: |
Line 2,450: |
| if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same | | if PublicationPlace == Place then Place = ''; end -- don't need both if they are the same |
| | | |
− | --[[ | + | --[[ |
− | Parameter remapping for cite encyclopedia: | + | Parameter remapping for cite encyclopedia: |
− | When the citation has these parameters: | + | When the citation has these parameters: |
− | |encyclopedia and |title then map |title to |article and |encyclopedia to |title
| + | |encyclopedia and |title then map |title to |article and |encyclopedia to |title |
− | |encyclopedia and |article then map |encyclopedia to |title
| + | |encyclopedia and |article then map |encyclopedia to |title |
− | |encyclopedia then map |encyclopedia to |title
| + | |encyclopedia then map |encyclopedia to |title |
− | | + | |
− | |trans_title maps to |trans_chapter when |title is re-mapped
| + | |trans-title maps to |trans-chapter when |title is re-mapped |
− | |url maps to |chapterurl when |title is remapped
| + | |url maps to |chapterurl when |title is remapped |
− | | + | |
− | All other combinations of |encyclopedia, |title, and |article are not modified | + | All other combinations of |encyclopedia, |title, and |article are not modified |
− | | + | |
− | ]] | + | ]] |
| | | |
| local Encyclopedia = A['Encyclopedia']; | | local Encyclopedia = A['Encyclopedia']; |
Line 2,410: |
Line 2,474: |
| TransChapter = TransTitle; | | TransChapter = TransTitle; |
| ChapterURL = URL; | | ChapterURL = URL; |
| + | ChapterUrlAccess = UrlAccess; |
| + | |
| if not is_set (ChapterURL) and is_set (TitleLink) then | | if not is_set (ChapterURL) and is_set (TitleLink) then |
− | Chapter= '[[' .. TitleLink .. '|' .. Chapter .. ']]'; | + | Chapter = make_wikilink (TitleLink, Chapter); |
| end | | end |
| Title = Periodical; | | Title = Periodical; |
Line 2,429: |
Line 2,495: |
| end | | end |
| | | |
− | -- Special case for cite techreport. | + | -- Special case for cite techreport. |
| if (config.CitationClass == "techreport") then -- special case for cite techreport | | if (config.CitationClass == "techreport") then -- special case for cite techreport |
| if is_set(A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' | | if is_set(A['Number']) then -- cite techreport uses 'number', which other citations alias to 'issue' |
Line 2,440: |
Line 2,506: |
| end | | end |
| | | |
− | -- special case for cite mailing list | + | -- special case for cite mailing list |
| if (config.CitationClass == "mailinglist") then | | if (config.CitationClass == "mailinglist") then |
| Periodical = A ['MailingList']; | | Periodical = A ['MailingList']; |
Line 2,447: |
Line 2,513: |
| end | | end |
| | | |
− | -- Account for the oddity that is {{cite conference}}, before generation of COinS data. | + | -- Account for the oddity that is {{cite conference}}, before generation of COinS data. |
| if 'conference' == config.CitationClass then | | if 'conference' == config.CitationClass then |
| if is_set(BookTitle) then | | if is_set(BookTitle) then |
Line 2,453: |
Line 2,519: |
| -- ChapterLink = TitleLink; -- |chapterlink= is deprecated | | -- ChapterLink = TitleLink; -- |chapterlink= is deprecated |
| ChapterURL = URL; | | ChapterURL = URL; |
| + | ChapterUrlAccess = UrlAccess; |
| ChapterURLorigin = URLorigin; | | ChapterURLorigin = URLorigin; |
| URLorigin = ''; | | URLorigin = ''; |
Line 2,467: |
Line 2,534: |
| end | | end |
| | | |
− | -- cite map oddities | + | -- cite map oddities |
| local Cartography = ""; | | local Cartography = ""; |
| local Scale = ""; | | local Scale = ""; |
Line 2,475: |
Line 2,542: |
| Chapter = A['Map']; | | Chapter = A['Map']; |
| ChapterURL = A['MapURL']; | | ChapterURL = A['MapURL']; |
| + | ChapterUrlAccess = UrlAccess; |
| TransChapter = A['TransMap']; | | TransChapter = A['TransMap']; |
| ChapterURLorigin = A:ORIGIN('MapURL'); | | ChapterURLorigin = A:ORIGIN('MapURL'); |
Line 2,489: |
Line 2,557: |
| end | | end |
| | | |
− | -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. | + | -- Account for the oddities that are {{cite episode}} and {{cite serial}}, before generation of COinS data. |
| 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']; |
Line 2,527: |
Line 2,595: |
| TransChapter = TransTitle; | | TransChapter = TransTitle; |
| ChapterURL = URL; | | ChapterURL = URL; |
| + | ChapterUrlAccess = UrlAccess; |
| ChapterURLorigin = A:ORIGIN('URL'); | | ChapterURLorigin = A:ORIGIN('URL'); |
| | | |
Line 2,534: |
Line 2,603: |
| | | |
| if is_set (ChapterLink) and not is_set (ChapterURL) then -- link but not URL | | if is_set (ChapterLink) and not is_set (ChapterURL) then -- link but not URL |
− | Chapter = '[[' .. ChapterLink .. '|' .. Chapter .. ']]'; -- ok to wikilink | + | Chapter = make_wikilink (ChapterLink, Chapter); |
| elseif is_set (ChapterLink) and is_set (ChapterURL) then -- if both are set, URL links episode; | | elseif is_set (ChapterLink) and is_set (ChapterURL) then -- if both are set, URL links episode; |
− | Series = '[[' .. ChapterLink .. '|' .. Series .. ']]'; -- series links with ChapterLink (episodelink -> TitleLink -> ChapterLink) ugly | + | Series = make_wikilink (ChapterLink, Series); |
| end | | end |
| URL = ''; -- unset | | URL = ''; -- unset |
Line 2,546: |
Line 2,615: |
| 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 |
− | Series = '[[' .. SeriesLink .. '|' .. Series .. ']]'; | + | Series = make_wikilink (SeriesLink, Series); |
| end | | end |
| Series = wrap_style ('italic-title', Series); -- series is italicized | | Series = wrap_style ('italic-title', Series); -- series is italicized |
| end | | end |
| end | | end |
− | -- end of {{cite episode}} stuff | + | -- end of {{cite episode}} stuff |
| | | |
− | -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, before generation of COinS data. | + | -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, {{cite citeseerx}}, before generation of COinS data. |
| do | | do |
| if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx'}) then | | if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx'}) then |
Line 2,563: |
Line 2,632: |
| Periodical = 'arXiv'; -- set to arXiv for COinS; after that, must be set to empty string | | Periodical = 'arXiv'; -- set to arXiv for COinS; after that, must be set to empty string |
| end | | end |
| + | |
| if 'biorxiv' == config.CitationClass then | | if 'biorxiv' == config.CitationClass then |
| Periodical = 'bioRxiv'; -- set to bioRxiv for COinS; after that, must be set to empty string | | Periodical = 'bioRxiv'; -- set to bioRxiv for COinS; after that, must be set to empty string |
| end | | end |
| + | |
| if 'citeseerx' == config.CitationClass then | | if 'citeseerx' == config.CitationClass then |
| Periodical = 'CiteSeerX'; -- set to CiteSeerX for COinS; after that, must be set to empty string | | Periodical = 'CiteSeerX'; -- set to CiteSeerX for COinS; after that, must be set to empty string |
Line 2,572: |
Line 2,643: |
| end | | end |
| | | |
− | -- handle type parameter for those CS1 citations that have default values | + | -- handle type parameter for those CS1 citations that have default values |
| if in_array(config.CitationClass, {"AV-media-notes", "interview", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then | | if in_array(config.CitationClass, {"AV-media-notes", "interview", "mailinglist", "map", "podcast", "pressrelease", "report", "techreport", "thesis"}) then |
| TitleType = set_titletype (config.CitationClass, TitleType); | | TitleType = set_titletype (config.CitationClass, TitleType); |
Line 2,585: |
Line 2,656: |
| end | | end |
| | | |
− | -- legacy: promote PublicationDate to Date if neither Date nor Year are set. | + | -- legacy: promote PublicationDate to Date if neither Date nor Year are set. |
| + | local Date_origin; -- to hold the name of parameter promoted to Date; required for date error messaging |
| + | |
| if not is_set (Date) then | | if not is_set (Date) then |
| Date = Year; -- promote Year to Date | | Date = Year; -- promote Year to Date |
Line 2,592: |
Line 2,665: |
| Date = PublicationDate; -- promote PublicationDate to Date | | Date = PublicationDate; -- promote PublicationDate to Date |
| PublicationDate = ''; -- unset, no longer needed | | PublicationDate = ''; -- unset, no longer needed |
| + | Date_origin = A:ORIGIN('PublicationDate'); -- save the name of the promoted parameter |
| + | else |
| + | Date_origin = A:ORIGIN('Year'); -- save the name of the promoted parameter |
| end | | end |
| + | else |
| + | Date_origin = A:ORIGIN('Date'); -- not a promotion; name required for error messaging |
| end | | end |
| | | |
| if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation | | if PublicationDate == Date then PublicationDate = ''; end -- if PublicationDate is same as Date, don't display in rendered citation |
| | | |
− | --[[ | + | --[[ |
− | Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where | + | Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates. This must be done before we do COinS because here is where |
− | we get the date used in the metadata. | + | we get the date used in the metadata. |
− | | + | |
− | Date validation supporting code is in Module:Citation/CS1/Date_validation | + | Date validation supporting code is in Module:Citation/CS1/Date_validation |
− | ]] | + | ]] |
| do -- create defined block to contain local variables error_message, date_parameters_list, mismatch | | do -- create defined block to contain local variables error_message, date_parameters_list, mismatch |
| 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 |
− | local date_parameters_list = {['access-date']=AccessDate, ['archive-date']=ArchiveDate, ['date']=Date, ['doi-broken-date']=DoiBroken, | + | local date_parameters_list = { |
− | ['embargo']=Embargo, ['lay-date']=LayDate, ['publication-date']=PublicationDate, ['year']=Year};
| + | ['access-date'] = {val=AccessDate, name=A:ORIGIN ('AccessDate')}, |
| + | ['archive-date'] = {val=ArchiveDate, name=A:ORIGIN ('ArchiveDate')}, |
| + | ['date'] = {val=Date, name=Date_origin}, |
| + | ['doi-broken-date'] = {val=DoiBroken, name=A:ORIGIN ('DoiBroken')}, |
| + | ['embargo'] = {val=Embargo, name=A:ORIGIN ('Embargo')}, |
| + | ['lay-date'] = {val=LayDate, name=A:ORIGIN ('LayDate')}, |
| + | ['publication-date'] ={val=PublicationDate, name=A:ORIGIN ('PublicationDate')}, |
| + | ['year'] = {val=Year, name=A:ORIGIN ('Year')}, |
| + | }; |
| + | anchor_year, Embargo, error_message = dates(date_parameters_list, COinS_date); |
| | | |
− | anchor_year, Embargo, error_message = dates(date_parameters_list, COinS_date); | + | -- start temporary Julian / Gregorian calendar uncertainty categorization |
| + | if COinS_date.inter_cal_cat then |
| + | add_prop_cat ('jul_greg_uncertainty'); |
| + | end |
| + | -- end temporary Julian / Gregorian calendar uncertainty categorization |
| | | |
| 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,625: |
Line 2,716: |
| if not is_set(error_message) then -- error free dates only | | if not is_set(error_message) then -- error free dates only |
| local modified = false; -- flag | | local modified = false; -- flag |
| + | |
| if is_set (DF) then -- if we need to reformat dates | | if is_set (DF) then -- if we need to reformat dates |
| modified = reformat_dates (date_parameters_list, DF, false); -- reformat to DF format, use long month names if appropriate | | modified = reformat_dates (date_parameters_list, DF, false); -- reformat to DF format, use long month names if appropriate |
| end | | end |
| | | |
− | if true == date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate | + | if true == date_hyphen_to_dash (date_parameters_list) then -- convert hyphens to dashes where appropriate |
| modified = true; | | modified = true; |
| add_maint_cat ('date_format'); -- hyphens were converted so add maint category | | add_maint_cat ('date_format'); -- hyphens were converted so add maint category |
| end | | end |
| | | |
| + | -- for those wikis that can and want to have English date names translated to the local language, |
| + | -- uncomment these three lines. Not supported by en.wiki (for obvious reasons) |
| + | -- set date_name_xlate() second argument to true to translate English digits to local digits (will translate ymd dates) |
| + | -- if date_name_xlate (date_parameters_list, false) then |
| + | -- modified = true; |
| + | -- end |
| + | |
| if modified then -- if the date_parameters_list values were modified | | if modified then -- if the date_parameters_list values were modified |
− | AccessDate = date_parameters_list['access-date']; -- overwrite date holding parameters with modified values | + | AccessDate = date_parameters_list['access-date'].val; -- overwrite date holding parameters with modified values |
− | ArchiveDate = date_parameters_list['archive-date']; | + | ArchiveDate = date_parameters_list['archive-date'].val; |
− | Date = date_parameters_list['date']; | + | Date = date_parameters_list['date'].val; |
− | DoiBroken = date_parameters_list['doi-broken-date']; | + | DoiBroken = date_parameters_list['doi-broken-date'].val; |
− | LayDate = date_parameters_list['lay-date']; | + | LayDate = date_parameters_list['lay-date'].val; |
− | PublicationDate = date_parameters_list['publication-date']; | + | PublicationDate = date_parameters_list['publication-date'].val; |
| end | | end |
| else | | else |
Line 2,647: |
Line 2,746: |
| end -- end of do | | end -- end of do |
| | | |
− | -- Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set. Do this after date check but before COInS. | + | -- Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set. Do this after date check but before COInS. |
− | -- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date | + | -- Here we unset Embargo if PMC not embargoed (|embargo= not set in the citation) or if the embargo time has expired. Otherwise, holds embargo date |
− | Embargo = is_embargoed (Embargo); -- | + | Embargo = is_embargoed (Embargo); |
| | | |
| if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then | | if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then |
Line 2,663: |
Line 2,762: |
| end | | end |
| | | |
− | -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. | + | -- At this point fields may be nil if they weren't specified in the template use. We can use that fact. |
| -- Test if citation has no title | | -- Test if citation has no title |
| if not is_set(Title) and | | if not is_set(Title) and |
Line 2,719: |
Line 2,818: |
| ['Volume'] = Volume, | | ['Volume'] = Volume, |
| ['Issue'] = Issue, | | ['Issue'] = Issue, |
− | ['Pages'] = get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links | + | ['Pages'] = coins_pages or get_coins_pages (first_set ({Sheet, Sheets, Page, Pages, At}, 5)), -- pages stripped of external links |
| ['Edition'] = Edition, | | ['Edition'] = Edition, |
| ['PublisherName'] = PublisherName, | | ['PublisherName'] = PublisherName, |
Line 2,728: |
Line 2,827: |
| }, config.CitationClass); | | }, config.CitationClass); |
| | | |
− | -- Account for the oddities that are {{cite arxiv}}, AFTER generation of COinS data. | + | -- Account for the oddities that are {{cite arxiv}}, {{cite biorxiv}}, and {{cite citeseerx}} AFTER generation of COinS data. |
− | -- if 'arxiv' == config.CitationClass then -- we have set rft.jtitle in COinS to arXiv, now unset so it isn't displayed
| |
| if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx'}) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, or CiteSeerX now unset so it isn't displayed | | if in_array (config.CitationClass, {'arxiv', 'biorxiv', 'citeseerx'}) then -- we have set rft.jtitle in COinS to arXiv, bioRxiv, or CiteSeerX now unset so it isn't displayed |
| Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal | | Periodical = ''; -- periodical not allowed in these templates; if article has been published, use cite journal |
| end | | end |
| | | |
− | -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text | + | -- special case for cite newsgroup. Do this after COinS because we are modifying Publishername to include some static text |
| if 'newsgroup' == config.CitationClass then | | if 'newsgroup' == config.CitationClass then |
| if is_set (PublisherName) then | | if is_set (PublisherName) then |
Line 2,809: |
Line 2,907: |
| 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, |
− | -- an error message if the associated url is not set, or an empty string for concatenation | + | -- 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'); | | ArchiveFormat = style_format (ArchiveFormat, ArchiveURL, 'archive-format', 'archive-url'); |
| ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); | | ConferenceFormat = style_format (ConferenceFormat, ConferenceURL, 'conference-format', 'conference-url'); |
Line 2,817: |
Line 2,915: |
| TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); | | TranscriptFormat = style_format (TranscriptFormat, TranscriptURL, 'transcript-format', 'transcripturl'); |
| | | |
− | -- special case for chapter format so no error message or cat when chapter not supported | + | -- 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', 'biorxiv', 'citeseerx'}) or | | if not (in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'arxiv', 'biorxiv', 'citeseerx'}) 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 |
Line 2,838: |
Line 2,936: |
| DeadURL = DeadURL:lower(); -- used later when assembling archived text | | DeadURL = DeadURL:lower(); -- used later when assembling archived text |
| if is_set( ArchiveURL ) then | | if is_set( ArchiveURL ) then |
− | if is_set (ChapterURL) then -- URL not set so if chapter-url is set apply archive url to it | + | if is_set (ChapterURL) then -- if chapter-url is set apply archive url to it |
| OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text | | OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text |
| OriginalURLorigin = ChapterURLorigin; -- name of chapter-url parameter for error messages | | OriginalURLorigin = ChapterURLorigin; -- name of chapter-url parameter for error messages |
− | OriginalFormat = ChapterFormat; -- and original |format= | + | OriginalFormat = ChapterFormat; -- and original |chapter-format= |
| if 'no' ~= DeadURL then | | if 'no' ~= DeadURL then |
| ChapterURL = ArchiveURL -- swap-in the archive's url | | ChapterURL = ArchiveURL -- swap-in the archive's url |
| ChapterURLorigin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages | | ChapterURLorigin = A:ORIGIN('ArchiveURL') -- name of archive-url parameter for error messages |
| ChapterFormat = ArchiveFormat or ''; -- swap in archive's format | | ChapterFormat = ArchiveFormat or ''; -- swap in archive's format |
| + | ChapterUrlAccess = nil; -- restricted access levels do not make sense for archived urls |
| end | | end |
| elseif is_set (URL) then | | elseif is_set (URL) then |
Line 2,892: |
Line 2,991: |
| end | | end |
| | | |
− | Chapter = format_chapter_title (ScriptChapter, Chapter, TransChapter, ChapterURL, ChapterURLorigin, no_quotes); -- Contribution is also in Chapter | + | Chapter = format_chapter_title (ScriptChapter, Chapter, TransChapter, ChapterURL, ChapterURLorigin, no_quotes, ChapterUrlAccess); -- Contribution is also in Chapter |
| if is_set (Chapter) then | | if is_set (Chapter) then |
| Chapter = Chapter .. ChapterFormat ; | | Chapter = Chapter .. ChapterFormat ; |
Line 2,905: |
Line 3,004: |
| | | |
| -- Format main title. | | -- Format main title. |
− | if is_set(TitleLink) and is_set(Title) then | + | if is_set (ArchiveURL) and mw.ustring.match (mw.ustring.lower(Title), cfg.special_case_translation['archived_copy']) then -- if title is 'Archived copy' (place holder added by bots that can't find proper title) |
− | Title = "[[" .. TitleLink .. "|" .. Title .. "]]" | + | add_maint_cat ('archived_copy'); -- add maintenance category before we modify the content of Title |
| end | | end |
| | | |
| + | if Title:match ('^%(%(.*%)%)$') then -- if keep as written markup: |
| + | Title= Title:gsub ('^%(%((.*)%)%)$', '%1') -- remove the markup |
| + | else |
| + | if '...' == Title:sub (-3) then -- if elipsis is the last three characters of |title= |
| + | Title = Title:gsub ('(%.%.%.)%.+$', '%1'); -- limit the number of dots to three |
| + | elseif not mw.ustring.find (Title, '%.%s*%a%.$') and -- end of title is not a 'dot-(optional space-)letter-dot' initialism ... |
| + | not mw.ustring.find (Title, '%s+%a%.$') then -- ...and not a 'space-letter-dot' initial (''Allium canadense'' L.) |
| + | Title = mw.ustring.gsub(Title, '%'..sepc..'$', ''); -- remove any trailing separator character; sepc and ms.ustring() here for languages that use multibyte separator characters |
| + | end |
| + | end |
| + | |
| if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx'}) or | | if in_array(config.CitationClass, {'web', 'news', 'journal', 'magazine', 'pressrelease', 'podcast', 'newsgroup', 'mailinglist', 'interview', 'arxiv', 'biorxiv', 'citeseerx'}) or |
| ('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or | | ('citation' == config.CitationClass and is_set (Periodical) and not is_set (Encyclopedia)) or |
Line 2,933: |
Line 3,043: |
| end | | end |
| end | | end |
− |
| + | |
| if is_set(Title) then | | if is_set(Title) then |
− | if not is_set(TitleLink) and is_set(URL) then | + | if not is_set (TitleLink) and is_set (URL) then |
− |
| + | Title = external_link (URL, Title, URLorigin, UrlAccess) .. TransTitle .. TransError .. Format; |
− | Title = external_link( URL, Title, URLorigin, UrlAccess ) .. TransTitle .. TransError .. Format; | + | URL = ''; -- unset these because no longer needed |
− | -- this experiment hidden 2016-04-10; see Help_talk:Citation_Style_1#Recycled_urls
| |
− | -- local temp_title = external_link( URL, Title, URLorigin ) .. TransError .. Format; -- do this so we get error message even if url is usurped no archive
| |
− | -- if in_array (DeadURL, {'unfit no archive', 'usurped no archive'}) then -- when url links to inappropriate location and there is no archive of original source available
| |
− | -- local err_msg
| |
− | -- if temp_title:match ('%[%S+%s+(.+)%](<.+)') then -- if there is an error message
| |
− | -- Title, err_msg = temp_title:match ('%[%S+%s+(.+)%](<.+)'); -- strip off external link; TODO: find a better to do this
| |
− | -- Title = Title .. (err_msg or '');
| |
− | -- end
| |
− | -- else
| |
− | -- Title = temp_title;
| |
− | -- end
| |
− | | |
− | URL = ''; -- unset these because no longer needed | |
| Format = ""; | | Format = ""; |
| + | elseif is_set (TitleLink) and not is_set (URL) then |
| + | local ws_url; |
| + | ws_url = wikisource_url_make (TitleLink); -- ignore ws_label return; not used here |
| + | if ws_url then |
| + | Title = external_link (ws_url, Title .. ' ', 'ws link in title-link'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? |
| + | Title = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], TitleLink, Title}); |
| + | Title = Title .. TransTitle .. TransError; |
| + | else |
| + | Title = make_wikilink (TitleLink, Title) .. TransTitle .. TransError; |
| + | end |
| else | | else |
− | Title = Title .. TransTitle .. TransError; | + | local ws_url, ws_label; |
| + | ws_url, ws_label, L = wikisource_url_make (Title); -- make ws url from |title= interwiki link; link portion L becomes tool tip label |
| + | if ws_url then |
| + | Title = Title:gsub ('%b[]', ws_label); -- replace interwiki link with ws_label to retain markup |
| + | Title = external_link (ws_url, Title .. ' ', 'ws link in title'); -- space char after Title to move icon away from italic text; TODO: a better way to do this? |
| + | Title = substitute (cfg.presentation['interwiki-icon'], {cfg.presentation['class-wikisource'], L, Title}); |
| + | Title = Title .. TransTitle .. TransError; |
| + | else |
| + | Title = Title .. TransTitle .. TransError; |
| + | end |
| end | | end |
| + | else |
| + | Title = TransTitle .. TransError; |
| end | | end |
| | | |
Line 2,996: |
Line 3,114: |
| end | | end |
| | | |
− | Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase, Mode); | + | Page, Pages, Sheet, Sheets = format_pages_sheets (Page, Pages, Sheet, Sheets, config.CitationClass, Periodical_origin, sepc, NoPP, use_lowercase); |
| | | |
| At = is_set(At) and (sepc .. " " .. At) or ""; | | At = is_set(At) and (sepc .. " " .. At) or ""; |
Line 3,029: |
Line 3,147: |
| | | |
| if is_set (Translators) then | | if is_set (Translators) then |
− | if 'mla' == Mode then | + | Others = safe_join ({sepc .. ' ', wrap_msg ('translated', Translators, use_lowercase), Others}, sepc); |
− | Others = sepc .. ' Trans. ' .. Translators .. Others;
| |
− | else
| |
− | Others = sepc .. ' ' .. wrap_msg ('translated', Translators, use_lowercase) .. Others;
| |
− | end
| |
| end | | end |
| if is_set (Interviewers) then | | if is_set (Interviewers) then |
− | Others = sepc .. ' ' .. wrap_msg ('interview', Interviewers, use_lowercase) .. Others; | + | Others = safe_join ({sepc .. ' ', wrap_msg ('interview', Interviewers, use_lowercase), Others}, sepc); |
| end | | end |
| | | |
Line 3,044: |
Line 3,158: |
| add_maint_cat ('extra_text', 'edition'); | | add_maint_cat ('extra_text', 'edition'); |
| end | | end |
− | if 'mla' == Mode then | + | Edition = " " .. wrap_msg ('edition', Edition); |
− | Edition = '. ' .. Edition .. ' ed.';
| |
− | else
| |
− | Edition = " " .. wrap_msg ('edition', Edition);
| |
− | end
| |
| else | | else |
| Edition = ''; | | Edition = ''; |
Line 3,054: |
Line 3,164: |
| | | |
| Series = is_set(Series) and (sepc .. " " .. Series) or ""; | | Series = is_set(Series) and (sepc .. " " .. Series) or ""; |
− | if 'mla' == Mode then -- not in brackets for mla
| + | OrigYear = is_set(OrigYear) and (" [" .. OrigYear .. "]") or ""; -- TODO: presentation |
− | OrigYear = is_set(OrigYear) and (". " .. OrigYear) or "";
| + | |
− | else
| |
− | OrigYear = is_set(OrigYear) and (" [" .. OrigYear .. "]") or ""; | |
− | end
| |
| Agency = is_set(Agency) and (sepc .. " " .. Agency) or ""; | | Agency = is_set(Agency) and (sepc .. " " .. Agency) or ""; |
| | | |
− | Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase, Mode); | + | Volume = format_volume_issue (Volume, Issue, config.CitationClass, Periodical_origin, sepc, use_lowercase); |
| | | |
| ------------------------------------ totally unrelated data | | ------------------------------------ totally unrelated data |
Line 3,068: |
Line 3,175: |
| end | | end |
| | | |
− | --[[ | + | --[[ |
− | Subscription implies paywall; Registration does not. If both are used in a citation, the subscription required link | + | Subscription implies paywall; Registration does not. If both are used in a citation, the subscription required link |
− | note is displayed. There are no error messages for this condition. | + | note is displayed. There are no error messages for this condition. |
− | | + | |
− | ]] | + | ]] |
| if is_set (SubscriptionRequired) then | | if is_set (SubscriptionRequired) then |
| SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message | | SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message |
Line 3,085: |
Line 3,192: |
| | | |
| AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format | | AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format |
− | if 'mla' == Mode then -- retrieved text not used in mla | + | if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if mode is cs2, lower case |
− | AccessDate = ' ' .. AccessDate;
| + | AccessDate = substitute (retrv_text, AccessDate); -- add retrieved text |
− | else
| + | |
− | if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if mode is cs2, lower case
| |
− | AccessDate = substitute (retrv_text, AccessDate); -- add retrieved text
| |
− | end
| |
| AccessDate = substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates | | AccessDate = substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates |
| end | | end |
Line 3,206: |
Line 3,310: |
| end | | end |
| | | |
− | --[[ | + | --[[ |
− | Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that | + | Handle the oddity that is cite speech. This code overrides whatever may be the value assigned to TitleNote (through |department=) and forces it to be " (Speech)" so that |
− | the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). | + | the annotation directly follows the |title= parameter value in the citation rather than the |event= parameter value (if provided). |
− | ]] | + | ]] |
| if "speech" == config.CitationClass then -- cite speech only | | if "speech" == config.CitationClass then -- cite speech only |
| TitleNote = " (Speech)"; -- annotate the citation | | TitleNote = " (Speech)"; -- annotate the citation |
Line 3,227: |
Line 3,331: |
| | | |
| if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then | | if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then |
− | if is_set(Others) then Others = Others .. sepc .. " " end | + | if is_set(Others) then Others = safe_join ({Others, sepc .. " "}, sepc) end -- add terminal punctuation & space; check for dup sepc; TODO why do we need to do this here? |
− | if 'mla' == Mode then
| + | tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc ); |
− | tcommon = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Edition, Publisher, Agency, Volume}, sepc );
| |
− | else | |
− | tcommon = safe_join( {Others, Title, TitleNote, Conference, Periodical, Format, TitleType, Series,
| |
− | Language, Edition, Publisher, Agency, Volume}, sepc );
| |
− | end
| |
| elseif in_array(config.CitationClass, {"book","citation"}) and not is_set(Periodical) then -- special cases for book cites | | 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 | | 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 | | tcommon = safe_join( {Title, TitleNote}, sepc ); -- author and other stuff will come after this and before tcommon2 |
− | if 'mla' == Mode then | + | tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc ); |
− | tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Edition, Publisher, Agency}, sepc );
| |
− | else
| |
− | tcommon2 = safe_join( {Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc );
| |
− | end
| |
− | elseif 'mla' == Mode then
| |
− | tcommon = safe_join( {TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Publisher, Agency}, sepc );
| |
| else | | else |
| tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc ); | | tcommon = safe_join( {Title, TitleNote, Conference, Periodical, Format, TitleType, Series, Language, Volume, Others, Edition, Publisher, Agency}, sepc ); |
Line 3,259: |
Line 3,352: |
| elseif 'episode' == config.CitationClass then -- special case for cite episode | | elseif 'episode' == config.CitationClass then -- special case for cite episode |
| tcommon = safe_join( {Title, TitleNote, TitleType, Series, Transcript, Language, Edition, Publisher}, sepc ); | | tcommon = safe_join( {Title, TitleNote, TitleType, Series, Transcript, Language, Edition, Publisher}, sepc ); |
− |
| |
− | elseif ('news' == config.CitationClass) and ('mla' == Mode) then -- special case for cite news in MLA mode
| |
− | tcommon = safe_join( {Periodical, Format, TitleType, Series, Language, Edition, Agency}, sepc );
| |
− |
| |
− | elseif ('web' == config.CitationClass) and ('mla' == Mode) then -- special case for cite web in MLA mode
| |
− | tcommon = safe_join( {Periodical, Format, TitleType, Series, Language,
| |
− | Edition, Publisher, Agency}, sepc );
| |
| | | |
| else -- all other CS1 templates | | else -- all other CS1 templates |
Line 3,283: |
Line 3,369: |
| | | |
| if is_set(Date) then | | if is_set(Date) then |
− | if ('mla' == Mode) then | + | if is_set (Authors) or is_set (Editors) then -- date follows authors or editors when authors not set |
− | if in_array (config.CitationClass, {'book', 'news', 'web'}) then
| |
− | Date = ', ' .. Date; -- origyear follows title in mla
| |
− | elseif 'journal' == config.CitationClass then
| |
− | Date = ', (' .. Date .. ')';
| |
− | end
| |
− | elseif is_set (Authors) or is_set (Editors) then -- date follows authors or editors when authors not set
| |
| Date = " (" .. Date ..")" .. OrigYear .. sepc .. " "; -- in paranetheses | | Date = " (" .. Date ..")" .. OrigYear .. sepc .. " "; -- in paranetheses |
| else -- neither of authors and editors set | | else -- neither of authors and editors set |
Line 3,300: |
Line 3,380: |
| end | | end |
| if is_set(Authors) then | | if is_set(Authors) then |
− | if (not is_set (Date)) or ('mla' == Mode) then -- when date is set it's in parentheses; no Authors termination | + | 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 | | Authors = terminate_name_list (Authors, sepc); -- when no date, terminate with 0 or 1 sepc and a space |
| end | | end |
Line 3,306: |
Line 3,386: |
| local in_text = " "; | | local in_text = " "; |
| local post_text = ""; | | local post_text = ""; |
− | if is_set(Chapter) and 0 == #c and 'mla' ~= Mode then | + | if is_set(Chapter) and 0 == #c then |
| in_text = in_text .. cfg.messages['in'] .. " " | | in_text = in_text .. cfg.messages['in'] .. " " |
− | if (sepc ~= '.') then in_text = in_text:lower() end -- lowercase for cs2 | + | if (sepc ~= '.') then |
− | elseif is_set(Chapter) and 'mla' == Mode then
| + | in_text = in_text:lower() -- lowercase for cs2 |
− | if EditorCount <= 1 then
| + | end |
− | in_text = '. Ed. ';
| |
− | else
| |
− | in_text = '. Eds. ';
| |
− | end
| |
| else | | else |
| if EditorCount <= 1 then | | if EditorCount <= 1 then |
Line 3,328: |
Line 3,404: |
| if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2 | | if (sepc ~= '.') then by_text = by_text:lower() end -- lowercase for cs2 |
| Authors = by_text .. Authors; -- author follows title so tweak it here | | Authors = by_text .. Authors; -- author follows title so tweak it here |
− | if is_set (Editors) and is_set (Date) and ('mla' ~= Mode) then -- when Editors make sure that Authors gets terminated | + | if is_set (Editors) and is_set (Date) then -- when Editors make sure that Authors gets terminated |
| Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space | | Authors = terminate_name_list (Authors, sepc); -- terminate with 0 or 1 sepc and a space |
| end | | end |
− | if (not is_set (Date)) or ('mla' == Mode) then -- when date is set it's in parentheses; no Contributors termination | + | 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 | | Contributors = terminate_name_list (Contributors, sepc); -- terminate with 0 or 1 sepc and a space |
| end | | end |
− | if 'mla' == Mode then | + | text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc ); |
− | text = safe_join( {Contributors, Chapter, tcommon, OrigYear, Authors, Place, Others, Editors, tcommon2, Date, pgtext, idcommon }, sepc );
| |
− | else
| |
− | text = safe_join( {Contributors, Date, Chapter, tcommon, Authors, Place, Editors, tcommon2, pgtext, idcommon }, sepc );
| |
− | end
| |
− | elseif 'mla' == Mode then
| |
− | tcommon = tcommon .. Date; -- hack to avoid duplicate separators
| |
− | text = safe_join( {Authors, Chapter, Title, OrigYear, Others, Editors, Edition, Place, tcommon, pgtext, idcommon }, sepc );
| |
| else | | else |
| text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); | | text = safe_join( {Authors, Date, Chapter, Place, Editors, tcommon, pgtext, idcommon }, sepc ); |
Line 3,359: |
Line 3,428: |
| end | | end |
| end | | end |
− | if 'mla' == Mode then | + | text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc ); |
− | if in_array(config.CitationClass, {'journal', 'news', 'web'}) and is_set(Periodical) then
| |
− | text = safe_join( {Editors, Title, Place, tcommon, pgtext, Date, idcommon}, sepc );
| |
− | else
| |
− | text = safe_join( {Editors, Chapter, Title, Place, tcommon, Date, pgtext, idcommon}, sepc );
| |
− | end
| |
− | else
| |
− | text = safe_join( {Editors, Date, Chapter, Place, tcommon, pgtext, idcommon}, sepc );
| |
− | end
| |
− | elseif 'mla' == Mode then
| |
− | if in_array(config.CitationClass, {'journal', 'news', 'web'}) and is_set(Periodical) then
| |
− | text = safe_join( {Title, Place, tcommon, pgtext, Date, idcommon}, sepc );
| |
− | else
| |
− | text = safe_join( {Chapter, Title, Place, tcommon, Date, pgtext, idcommon}, sepc );
| |
− | end
| |
| else | | else |
| if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then | | if in_array(config.CitationClass, {"journal","citation"}) and is_set(Periodical) then |
Line 3,427: |
Line 3,482: |
| end | | end |
| | | |
| + | local render = {}; -- here we collect the final bits for concatenation into the rendered citation |
| + | |
| if is_set(options.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags | | if is_set(options.id) then -- here we wrap the rendered citation in <cite ...>...</cite> tags |
− | text = substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options.id), mw.text.nowiki(options.class), text}); -- when |ref= is set | + | table.insert (render, substitute (cfg.presentation['cite-id'], {mw.uri.anchorEncode(options.id), mw.text.nowiki(options.class), text})); -- when |ref= is set |
| else | | else |
− | text = substitute (cfg.presentation['cite'], {mw.text.nowiki(options.class), text}); -- all other cases | + | table.insert (render, substitute (cfg.presentation['cite'], {mw.text.nowiki(options.class), text})); -- all other cases |
| end | | end |
| | | |
− | text = text .. substitute (cfg.presentation['ocins'], {OCinSoutput}); -- append metadata to the citation | + | table.insert (render, substitute (cfg.presentation['ocins'], {OCinSoutput})); -- append metadata to the citation |
− |
| + | |
− | if #z.message_tail ~= 0 then | + | if 0 ~= #z.message_tail then |
− | text = text .. " "; | + | table.insert (render, ' '); |
| for i,v in ipairs( z.message_tail ) do | | for i,v in ipairs( z.message_tail ) do |
| if is_set(v[1]) then | | if is_set(v[1]) then |
| if i == #z.message_tail then | | if i == #z.message_tail then |
− | text = text .. error_comment( v[1], v[2] ); | + | table.insert (render, error_comment( v[1], v[2] )); |
| else | | else |
− | text = text .. error_comment( v[1] .. "; ", v[2] ); | + | table.insert (render, error_comment( v[1] .. "; ", v[2] )); |
| end | | end |
| end | | end |
Line 3,448: |
Line 3,505: |
| end | | end |
| | | |
− | if #z.maintenance_cats ~= 0 then | + | if 0 ~= #z.maintenance_cats then |
− | text = text .. '<span class="citation-comment" style="display:none; color:#33aa33; margin-left:0.3em">'; | + | local maint_msgs = {}; -- here we collect all of the maint messages |
| for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories | | for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories |
− | text = text .. v .. ' ([[:Category:' .. v ..'|link]])'; | + | local maint = {}; -- here we assemble a maintenence message |
| + | table.insert (maint, v); -- maint msg is the category name |
| + | table.insert (maint, ' ('); -- open the link text |
| + | table.insert (maint, make_wikilink (':Category:' .. v, 'link')); -- add the link |
| + | table.insert (maint, ')'); -- and close it |
| + | table.insert (maint_msgs, table.concat (maint)); -- assemble new maint message and add it to the maint_msgs table |
| end | | end |
− | text = text .. '</span>'; -- maintenance mesages (realy just the names of the categories for now) | + | table.insert (render, substitute (cfg.presentation['hidden-maint'], table.concat (maint_msgs, ' '))); -- wrap the group of maint message with proper presentation and save |
| end | | end |
| | | |
Line 3,459: |
Line 3,521: |
| if in_array(no_tracking_cats, {"", "no", "false", "n"}) then | | if in_array(no_tracking_cats, {"", "no", "false", "n"}) then |
| for _, v in ipairs( z.error_categories ) do | | for _, v in ipairs( z.error_categories ) do |
− | text = text .. '[[Category:' .. v ..']]'; | + | table.insert (render, make_wikilink ('Category:' .. v)); |
| end | | end |
| for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories | | for _, v in ipairs( z.maintenance_cats ) do -- append maintenance categories |
− | text = text .. '[[Category:' .. v ..']]'; | + | table.insert (render, make_wikilink ('Category:' .. v)); |
| end | | end |
− | for _, v in ipairs( z.properties_cats ) do -- append maintenance categories | + | for _, v in ipairs( z.properties_cats ) do -- append properties categories |
− | text = text .. '[[Category:' .. v ..']]'; | + | table.insert (render, make_wikilink ('Category:' .. v)); |
| end | | end |
| end | | end |
− |
| + | |
− | return text | + | return table.concat (render); |
| end | | end |
| | | |
| | | |
− | --[[--------------------------< C S 1 . C I T A T I O N >------------------------------------------------------ | + | --[[--------------------------< V A L I D A T E >-------------------------------------------------------------- |
| | | |
− | This is used by templates such as {{cite book}} to create the actual citation text.
| + | Looks for a parameter's name in one of several whitelists. |
| | | |
| + | Parameters in the whitelist can have three values: |
| + | true - active, supported parameters |
| + | false - deprecated, supported parameters |
| + | nil - unsupported parameters |
| + | |
| ]] | | ]] |
| | | |
− | function cs1.citation(frame) | + | local function validate (name, cite_class) |
− | Frame = frame; -- save a copy incase we need to display an error message in preview mode
| + | local name = tostring (name); |
− | local pframe = frame:getParent() | + | local state; |
− | local validation, utilities, identifiers, metadata; | |
| | | |
− | if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version? | + | if in_array (cite_class, {'arxiv', 'biorxiv', 'citeseerx'}) then -- limited parameter sets allowed for these templates |
− | cfg = mw.loadData ('Module:Citation/CS1/Configuration/sandbox'); -- load sandbox versions of support modules | + | state = whitelist.limited_basic_arguments[name]; |
− | whitelist = mw.loadData ('Module:Citation/CS1/Whitelist/sandbox'); | + | if true == state then return true; end -- valid actively supported parameter |
− | utilities = require ('Module:Citation/CS1/Utilities/sandbox'); | + | if false == state then |
− | validation = require ('Module:Citation/CS1/Date_validation/sandbox'); | + | deprecated_parameter (name); -- parameter is deprecated but still supported |
− | identifiers = require ('Module:Citation/CS1/Identifiers/sandbox'); | + | return true; |
− | metadata = require ('Module:Citation/CS1/COinS/sandbox'); | + | end |
| + | |
| + | state = whitelist[cite_class .. '_basic_arguments'][name]; -- look in the parameter-list for the template identified by cite_class |
| + | |
| + | if true == state then return true; end -- valid actively supported parameter |
| + | if false == state then |
| + | deprecated_parameter (name); -- parameter is deprecated but still supported |
| + | return true; |
| + | end |
| + | -- limited enumerated parameters list |
| + | name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) |
| + | state = whitelist.limited_numbered_arguments[name]; |
| + | if true == state then return true; end -- valid actively supported parameter |
| + | if false == state then |
| + | deprecated_parameter (name); -- parameter is deprecated but still supported |
| + | return true; |
| + | end |
| + | |
| + | return false; -- not supported because not found or name is set to nil |
| + | end -- end limited parameter-set templates |
| | | |
− | else -- otherwise | + | state = whitelist.basic_arguments[name]; -- all other templates; all normal parameters allowed |
− | cfg = mw.loadData ('Module:Citation/CS1/Configuration'); -- load live versions of support modules
| + | |
− | whitelist = mw.loadData ('Module:Citation/CS1/Whitelist');
| + | if true == state then return true; end -- valid actively supported parameter |
− | utilities = require ('Module:Citation/CS1/Utilities');
| + | if false == state then |
− | validation = require ('Module:Citation/CS1/Date_validation');
| + | deprecated_parameter (name); -- parameter is deprecated but still supported |
− | identifiers = require ('Module:Citation/CS1/Identifiers'); | + | return true; |
− | metadata = require ('Module:Citation/CS1/COinS'); | |
| end | | end |
| + | -- all enumerated parameters allowed |
| + | name = name:gsub("%d+", "#" ); -- replace digit(s) with # (last25 becomes last#) (mw.ustring because non-Western 'local' digits) |
| + | state = whitelist.numbered_arguments[name]; |
| | | |
− | utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the cfg tables | + | if true == state then return true; end -- valid actively supported parameter |
− | identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module | + | if false == state then |
− | validation.set_selected_modules (utilities); -- so that functions in Date validataion can see the selected Utilities module | + | deprecated_parameter (name); -- parameter is deprecated but still supported |
− | metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module | + | return true; |
| + | end |
| + | |
| + | return false; -- not supported because not found or name is set to nil |
| + | end |
| | | |
− | dates = validation.dates; -- imported functions from Module:Citation/CS1/Date validation
| |
− | year_date_check = validation.year_date_check;
| |
− | reformat_dates = validation.reformat_dates;
| |
− | date_hyphen_to_dash = validation.date_hyphen_to_dash;
| |
− |
| |
− | is_set = utilities.is_set; -- imported functions from Module:Citation/CS1/Utilities
| |
− | in_array = utilities.in_array;
| |
− | substitute = utilities.substitute;
| |
− | error_comment = utilities.error_comment;
| |
− | set_error = utilities.set_error;
| |
− | select_one = utilities.select_one;
| |
− | add_maint_cat = utilities.add_maint_cat;
| |
− | wrap_style = utilities.wrap_style;
| |
− | safe_for_italics = utilities.safe_for_italics;
| |
− | remove_wiki_link = utilities.remove_wiki_link;
| |
| | | |
− | z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities | + | --[[--------------------------< M I S S I N G _ P I P E _ C H E C K >------------------------------------------ |
| + | |
| + | Look at the contents of a parameter. If the content has a string of characters and digits followed by an equal |
| + | sign, compare the alphanumeric string to the list of cs1|2 parameters. If found, then the string is possibly a |
| + | parameter that is missing its pipe: |
| + | {{cite ... |title=Title access-date=2016-03-17}} |
| + | |
| + | cs1|2 shares some parameter names with xml/html atributes: class=, title=, etc. To prevent false positives xml/html |
| + | tags are removed before the search. |
| + | |
| + | If a missing pipe is detected, this function adds the missing pipe maintenance category. |
| + | |
| + | ]] |
| + | |
| + | local function missing_pipe_check (value) |
| + | local capture; |
| + | value = value:gsub ('%b<>', ''); -- remove xml/html tags because attributes: class=, title=, etc |
| | | |
− | extract_ids = identifiers.extract_ids; -- imported functions from Module:Citation/CS1/Identifiers | + | capture = value:match ('%s+(%a[%a%d]+)%s*=') or value:match ('^(%a[%a%d]+)%s*='); -- find and categorize parameters with possible missing pipes |
− | build_id_list = identifiers.build_id_list; | + | if capture and validate (capture) then -- if the capture is a valid parameter name |
− | is_embargoed = identifiers.is_embargoed; | + | add_maint_cat ('missing_pipe'); |
− | extract_id_access_levels = identifiers.extract_id_access_levels; | + | end |
| + | end |
| + | |
| + | |
| + | --[[--------------------------< C S 1 . C I T A T I O N >------------------------------------------------------ |
| + | |
| + | This is used by templates such as {{cite book}} to create the actual citation text. |
| + | |
| + | ]] |
| + | |
| + | function cs1.citation(frame) |
| + | Frame = frame; -- save a copy incase we need to display an error message in preview mode |
| + | local pframe = frame:getParent() |
| + | local validation, utilities, identifiers, metadata, styles; |
| | | |
− | make_coins_title = metadata.make_coins_title; -- imported functions from Module:Citation/CS1/COinS | + | if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version? |
− | get_coins_pages = metadata.get_coins_pages; | + | cfg = mw.loadData ('Module:Citation/CS1/Configuration/sandbox'); -- load sandbox versions of support modules |
− | COinS = metadata.COinS; | + | whitelist = mw.loadData ('Module:Citation/CS1/Whitelist/sandbox'); |
− | | + | utilities = require ('Module:Citation/CS1/Utilities/sandbox'); |
− | local args = {}; -- table where we store all of the template's arguments | + | validation = require ('Module:Citation/CS1/Date_validation/sandbox'); |
− | local suggestions = {}; -- table where we store suggestions if we need to loadData them | + | identifiers = require ('Module:Citation/CS1/Identifiers/sandbox'); |
− | local error_text, error_state; | + | metadata = require ('Module:Citation/CS1/COinS/sandbox'); |
− | | + | styles = 'Module:Citation/CS1/sandbox/styles.css'; |
− | local config = {}; -- table to store parameters from the module {{#invoke:}} | + | |
− | for k, v in pairs( frame.args ) do | + | else -- otherwise |
− | config[k] = v; | + | cfg = mw.loadData ('Module:Citation/CS1/Configuration'); -- load live versions of support modules |
− | -- args[k] = v; -- debug tool that allows us to render a citation from module {{#invoke:}} | + | whitelist = mw.loadData ('Module:Citation/CS1/Whitelist'); |
− | end | + | utilities = require ('Module:Citation/CS1/Utilities'); |
− | | + | validation = require ('Module:Citation/CS1/Date_validation'); |
− | local capture; -- the single supported capture when matching unknown parameters using patterns | + | identifiers = require ('Module:Citation/CS1/Identifiers'); |
− | for k, v in pairs( pframe.args ) do | + | metadata = require ('Module:Citation/CS1/COinS'); |
− | if v ~= '' then | + | styles = 'Module:Citation/CS1/styles.css'; |
− | if not validate( k, config.CitationClass ) then | + | |
− | error_text = ""; | + | end |
− | if type( k ) ~= 'string' then | + | |
− | -- Exclude empty numbered parameters | + | utilities.set_selected_modules (cfg); -- so that functions in Utilities can see the cfg tables |
− | if v:match("%S+") ~= nil then | + | identifiers.set_selected_modules (cfg, utilities); -- so that functions in Identifiers can see the selected cfg tables and selected Utilities module |
− | error_text, error_state = set_error( 'text_ignored', {v}, true ); | + | validation.set_selected_modules (cfg, utilities); -- so that functions in Date validataion can see selected cfg tables and the selected Utilities module |
− | end | + | metadata.set_selected_modules (cfg, utilities); -- so that functions in COinS can see the selected cfg tables and selected Utilities module |
− | elseif validate( k:lower(), config.CitationClass ) then | + | |
− | error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true ); | + | dates = validation.dates; -- imported functions from Module:Citation/CS1/Date validation |
− | else | + | year_date_check = validation.year_date_check; |
− | if nil == suggestions.suggestions then -- if this table is nil then we need to load it | + | reformat_dates = validation.reformat_dates; |
− | if nil ~= string.find (frame:getTitle(), 'sandbox', 1, true) then -- did the {{#invoke:}} use sandbox version? | + | date_hyphen_to_dash = validation.date_hyphen_to_dash; |
− | suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions/sandbox' ); -- use the sandbox version | + | date_name_xlate = validation.date_name_xlate; |
− | else | + | |
− | suggestions = mw.loadData( 'Module:Citation/CS1/Suggestions' ); -- use the live version | + | is_set = utilities.is_set; -- imported functions from Module:Citation/CS1/Utilities |
− | end | + | in_array = utilities.in_array; |
− | end | + | substitute = utilities.substitute; |
− | for pattern, param in pairs (suggestions.patterns) do -- loop through the patterns to see if we can suggest a proper parameter | + | error_comment = utilities.error_comment; |
− | capture = k:match (pattern); -- the whole match if no caputre in pattern else the capture if a match | + | set_error = utilities.set_error; |
− | if capture then -- if the pattern matches | + | select_one = utilities.select_one; |
− | param = substitute( param, capture ); -- add the capture to the suggested parameter (typically the enumerator) | + | add_maint_cat = utilities.add_maint_cat; |
− | error_text, error_state = set_error( 'parameter_ignored_suggest', {k, param}, true ); -- set the error message | + | wrap_style = utilities.wrap_style; |
| + | safe_for_italics = utilities.safe_for_italics; |
| + | is_wikilink = utilities.is_wikilink; |
| + | make_wikilink = utilities.make_wikilink; |
| + | |
| + | z = utilities.z; -- table of error and category tables in Module:Citation/CS1/Utilities |
| + | |
| + | extract_ids = identifiers.extract_ids; -- imported functions from Module:Citation/CS1/Identifiers |
| + | build_id_list = identifiers.build_id_list; |
| + | is_embargoed = identifiers.is_embargoed; |
| + | extract_id_access_levels = identifiers.extract_id_access_levels; |
| + | |
| + | make_coins_title = metadata.make_coins_title; -- imported functions from Module:Citation/CS1/COinS |
| + | get_coins_pages = metadata.get_coins_pages; |
| + | COinS = metadata.COinS; |
| + | |
| + | local args = {}; -- table where we store all of the template's arguments |
| + | local suggestions = {}; -- table where we store suggestions if we need to loadData them |
| + | local error_text, error_state; |
| + | |
| + | local config = {}; -- table to store parameters from the module {{#invoke:}} |
| + | for k, v in pairs( frame.args ) do |
| + | config[k] = v; |
| + | -- args[k] = v; -- debug tool that allows us to render a citation from module {{#invoke:}} |
| + | end |
| + | |
| + | local capture; -- the single supported capture when matching unknown parameters using patterns |
| + | for k, v in pairs( pframe.args ) do |
| + | if v ~= '' then |
| + | if ('string' == type (k)) then |
| + | k = mw.ustring.gsub (k, '%d', cfg.date_names.local_digits); -- for enumerated parameters, translate 'local' digits to Western 0-9 |
| + | end |
| + | if not validate( k, config.CitationClass ) then |
| + | error_text = ""; |
| + | if type( k ) ~= 'string' then |
| + | -- Exclude empty numbered parameters |
| + | if v:match("%S+") ~= nil then |
| + | error_text, error_state = set_error( 'text_ignored', {v}, true ); |
| + | end |
| + | elseif validate( k:lower(), config.CitationClass ) then |
| + | error_text, error_state = set_error( 'parameter_ignored_suggest', {k, k:lower()}, true ); -- suggest the lowercase version of the parameter |
| + | else |
| + | if nil == suggestions.suggestions then -- if this table is nil then we need to load it |
| + | 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) |
| + | if validate (param, config.CitationClass) then -- validate the suggestion to make sure that the suggestion is supported by this template (necessary for limited parameter lists) |
| + | error_text, error_state = set_error ('parameter_ignored_suggest', {k, param}, true); -- set the suggestion error message |
| + | else |
| + | error_text, error_state = set_error( 'parameter_ignored', {param}, true ); -- suggested param not supported by this template |
| + | end |
| end | | end |
| end | | end |
Line 3,584: |
Line 3,746: |
| end | | end |
| missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe? | | missing_pipe_check (v); -- do we think that there is a parameter that is missing a pipe? |
− |
| + | -- TODO: is this the best place for this translation? |
− | args[k] = v;
| |
− | elseif args[k] ~= nil or (k == 'postscript') then
| |
| args[k] = v; | | args[k] = v; |
| + | elseif args[k] ~= nil or (k == 'postscript') then -- here when v is empty string |
| + | args[k] = v; -- why do we do this? we don't support 'empty' parameters |
| end | | end |
| end | | end |
Line 3,596: |
Line 3,758: |
| end | | end |
| end | | end |
− | return citation0( config, args) | + | return table.concat ({citation0( config, args), frame:extensionTag ('templatestyles', '', {src=styles})}); |
| end | | end |
| | | |
| return cs1; | | return cs1; |