Module:Citation/CS1: Difference between revisions

    m>Trappist the monk
    (Better version of strip_apostrophe_markup()?)
    m>Trappist the monk
    (Synch from sandbox;)
    Line 37: Line 37:


    --[[
    --[[
    Categorize and emit an error message when the citation contains one or more deprecated parameters.  Because deprecated parameters (currently |day=, |month=,
    Categorize and emit an error message when the citation contains one or more deprecated parameters.  Because deprecated parameters (currently |month=,
    |coauthor=, and |coauthors=) aren't related to each other and because these parameters may be concatenated into the variables used by |date= and |author#= (and aliases)
    |coauthor=, and |coauthors=) aren't related to each other and because these parameters may be concatenated into the variables used by |date= and |author#= (and aliases)
    details of which parameter caused the error message are not provided.  Only one error message is emitted regardless of the number of deprecated parameters in the citation.
    details of which parameter caused the error message are not provided.  Only one error message is emitted regardless of the number of deprecated parameters in the citation.
    Line 50: Line 50:
    -- Populates numbered arguments in a message string using an argument table.
    -- Populates numbered arguments in a message string using an argument table.
    function substitute( msg, args )
    function substitute( msg, args )
    -- return args and tostring( mw.message.newRawMessage( msg, args ) ) or msg;
    return args and mw.message.newRawMessage( msg, args ):plain() or msg;
    return args and mw.message.newRawMessage( msg, args ):plain() or msg;
    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.
    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'"
    " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example)
    " 'Kerned title with leading and trailing single quote marks' " (in real life the kerning isn't as wide as this example)
    Double single quotes (italic or bold wikimarkup) are not kerned.
    Call this function for chapter titles, for website titles, etc; not for book titles.
    ]]
    ]]
    function kern_quotes (str)
    function kern_quotes (str)
    local left='<span style="padding-left:0.2em;">%1</span>'; -- spacing to use when title contains leading single or double quote mark
    local cap='';
    local right='<span style="padding-right:0.2em;">%1</span>'; -- spacing to use when title contains trailing single or double quote mark
    local cap2='';
    if  str:match ("^[\"\'][^\']") then
    cap, cap2 = str:match ("^([\"\'])([^\'].+)"); -- match leading double or single quote but not double single quotes
    str = string.gsub( str, "^[\"\']", left, 1 ); -- replace (captured) leading single or double quote with left-side <span>
    if is_set (cap) then
    str = substitute (cfg.presentation['kern-left'], {cap, cap2});
    end
    end
    if str:match ("[^\'][\"\']$") then
     
    str = string.gsub( str, "[\"\']$", right, 1 ); -- replace (captured) trailing single or double quote with right-side <span>
    cap, cap2 = str:match ("^(.+[^\'])([\"\'])$")
    if is_set (cap) then
    str = substitute (cfg.presentation['kern-right'], {cap, cap2});
    end
    end
    return str;
    return str;
    Line 110: Line 118:
    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
    if inArray (lang, {'ar', 'ja', 'ko', 'he', 'zh'}) then -- is prefix one of these language codes?
    -- is prefix one of these language codes?
    if inArray (lang, {'ar', 'bs', 'dv', 'el', 'fa', 'hy', 'ja', 'ko', 'ku', 'he', 'ps', 'ru', 'sd', 'sr', 'th', 'uk', 'ug', 'yi', 'zh'}) then
    table.insert( z.properties_cats, 'CS1 uses ' .. name .. '-language script ('..lang..')'); -- categorize in language-specific categories
    table.insert( z.properties_cats, 'CS1 uses ' .. name .. '-language script ('..lang..')'); -- categorize in language-specific categories
    else
    else
    Line 120: Line 129:
    end
    end
    end
    end
    script_value = '<bdi' .. lang .. '>' .. script_value .. '</bdi>'; -- isolate incase script is rlt
    script_value = substitute (cfg.presentation['bdi'], {lang, script_value}); -- isolate in case script is rtl


    return script_value;
    return script_value;
    Line 141: Line 150:
    end
    end


    -- Wraps a string using a message_list configuration taking one argument
     
    function wrap( key, str, lower )
    --[[--------------------------< W R A P _ S T Y L E >----------------------------------------------------------
     
    Applies styling to various parameters.  Supplied string is wrapped using a message_list configuration taking one
    argument; protects italic styled parameters.  Additional text taken from citation_config.presentation - the reason
    this function is similar to but separate from wrap_msg().
     
    ]]
     
    function wrap_style (key, str)
    if not is_set( str ) then
    if not is_set( str ) then
    return "";
    return "";
    Line 148: Line 165:
    str = safeforitalics( str );
    str = safeforitalics( str );
    end
    end
    if lower == true then
     
    return substitute( cfg.messages[key]:lower(), {str} );
    return substitute( cfg.presentation[key], {str} );
    end
     
     
    --[[--------------------------< W R A P _ M S G >--------------------------------------------------------------
     
    Applies additional message text to various parameter values. Supplied string is wrapped using a message_list
    configuration taking one argument.  Supports lower case text for {{citation}} templates.  Additional text taken
    from citation_config.messages - the reason this function is similar to but separate from wrap_style().
     
    ]]
     
    function wrap_msg (key, str, lower)
    if not is_set( str ) then
    return "";
    end
    if true == lower then
    local msg;
    msg = cfg.messages[key]:lower(); -- set the message to lower case before
    str = substitute( msg, {str} ); -- including template text
    return str;
    else
    else
    return substitute( cfg.messages[key], {str} );
    return substitute( cfg.messages[key], {str} );
    Line 155: Line 192:
    end
    end


    --[[
    --[[--------------------------< F O R M A T _ C H A P T E R _ T I T L E >--------------------------------------
    Argument wrapper.  This function provides support for argument
     
    mapping defined in the configuration file so that multiple names
    Format the three chapter parameters: |chapter=, |trans-chapter=, and |chapter-url= into a single Chapter meta-
    can be transparently aliased to single internal variable.
    parameter (chapter_url_source used for error messages).
     
    ]]
    ]]
    function argument_wrapper( args )
     
    function format_chapter_title (chapter, transchapter, chapterurl, chapter_url_source)
    local chapter_error = '';
    if not is_set (chapter) then
    chapter = ''; -- just to be safe for concatenation
    if is_set (transchapter) then
    chapter = wrap_style ('trans-quoted-title', transchapter);
    chapter_error = " " .. seterror ('trans_missing_chapter');
    end
    if is_set (chapterurl) then
    chapter = externallink (chapterurl, chapter, chapter_url_source); -- adds bare_url_missing_title error if appropriate
    end
    return chapter .. chapter_error;
    else -- here when chapter is set
    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);
    if is_set (transchapter) then
    transchapter = wrap_style ('trans-quoted-title', transchapter);
    chapter = chapter .. ' ' .. transchapter;
    end
    if is_set (chapterurl) then
    chapter = externallink (chapterurl, chapter); -- adds bare_url_missing_title error if appropriate
    end
    end
    return chapter;
    end
     
    --[[
    Argument wrapper.  This function provides support for argument
    mapping defined in the configuration file so that multiple names
    can be transparently aliased to single internal variable.
    ]]
    function argument_wrapper( args )
    local origin = {};
    local origin = {};
    Line 233: Line 304:
    end
    end


    -- Formats a comment for error trapping
    --[[--------------------------< E R R O R C O M M E N T >------------------------------------------------------
     
    Wraps error messages with css markup according to the state of hidden.
     
    ]]
    function errorcomment( content, hidden )
    function errorcomment( content, hidden )
    return wrap( hidden and 'hidden-error' or 'visible-error', content );
    return substitute( hidden and cfg.presentation['hidden-error'] or cfg.presentation['visible-error'], content );
    end
    end


    Line 303: Line 378:
    label = URL;
    label = URL;
    if is_set( source ) then
    if is_set( source ) then
    error_str = seterror( 'bare_url_missing_title', { wrap( 'parameter', source ) }, false, " " );
    error_str = seterror( 'bare_url_missing_title', { wrap_style ('parameter', source) }, false, " " );
    else
    else
    error( cfg.messages["bare_url_no_origin"] );
    error( cfg.messages["bare_url_no_origin"] );
    Line 314: Line 389:
    end
    end


    -- Formats a link to Amazon
    --[[--------------------------< N O W R A P _ D A T E >--------------------------------------------------------
    function amazon(id, domain)
     
    if checkisbn( id ) then -- see if asin value is a 10-digit isbn
    When date is YYYY-MM-DD format wrap in nowrap span: <span ...>YYYY-MM-DD</span>.  When date is DD MMMM YYYY or is
    table.insert( z.maintenance_cats, "CS1 maint: ASIN uses ISBN"); -- add to maint category so a bot or awb script can replace |asin= with |isbn=
    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.
     
    ]]
     
    function nowrap_date (date)
    local cap='';
    local cap2='';
     
    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
    end
    if not is_set(domain) then  
    domain = "com";
    return date;
    elseif inArray (domain, {'jp', 'uk'}) then -- Japan, United Kingdom
    end
    domain = "co." .. domain;
     
    --[[--------------------------< A M A Z O N >------------------------------------------------------------------
     
    Formats a link to Amazon.  Do simple error checking: asin must be mix of 10 numeric or uppercase alpha
    characters.  If a mix, first character must be uppercase alpha; if all numeric, asins must be 10-digit
    isbn. If 10-digit isbn, add a maintenance category so a bot or awb script can replace |asin= with |isbn=.
    Error message if not 10 characters, if not isbn10, if mixed and first character is a digit.
     
    ]]
     
    function amazon(id, domain)
    local err_cat = ""
     
    if not id:match("^[%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u][%d%u]$") then
    err_cat =  ' ' .. seterror ('bad_asin'); -- asin is not a mix of 10 uppercase alpha and numeric characters
    else
    if id:match("^%d%d%d%d%d%d%d%d%d%d$") then -- if 10-digit numeric
    if checkisbn( id ) then -- see if asin value is isbn10
    table.insert( z.maintenance_cats, "CS1 maint: ASIN uses ISBN"); -- add to maint category
    elseif not is_set (err_cat) then
    err_cat =  ' ' .. seterror ('bad_asin'); -- asin is not isbn10
    end
    elseif not id:match("^%u[%d%u]+$") then
    err_cat =  ' ' .. seterror ('bad_asin'); -- asin doesn't begin with uppercase alpha
    end
    end
    if not is_set(domain) then  
    domain = "com";
    elseif inArray (domain, {'jp', 'uk'}) then -- Japan, United Kingdom
    domain = "co." .. domain;
    elseif inArray (domain, {'au', 'br', 'mx'}) then -- Australia, Brazil, Mexico
    elseif inArray (domain, {'au', 'br', 'mx'}) then -- Australia, Brazil, Mexico
    domain = "com." .. domain;
    domain = "com." .. domain;
    Line 329: Line 448:
    return externallinkid({link = handler.link,
    return externallinkid({link = handler.link,
    label=handler.label , prefix="//www.amazon."..domain.."/dp/",id=id,
    label=handler.label , prefix="//www.amazon."..domain.."/dp/",id=id,
    encode=handler.encode, separator = handler.separator})
    encode=handler.encode, separator = handler.separator}) .. err_cat;
    end
    end


    Line 647: Line 766:
    return text
    return text
    end
    end
    --[[--------------------------< M E S S A G E _ I D >----------------------------------------------------------
    Validate and format a usenet message id.  Simple error checking, looks for 'id-left@id-right' not enclosed in
    '<' and/or '>' angle brackets.
    ]]
    function message_id (id)
    local handler = cfg.id_handlers['USENETID'];
    text = externallinkid({link = handler.link, label = handler.label,
    prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
    if not id:match('^.+@.+$') or not id:match('^[^<].*[^>]$')then -- doesn't have '@' or has one or first or last character is '< or '>'
    text = text .. ' ' .. seterror( 'bad_message_id' ) -- add an error message if the message id is invalid
    end
    return text
    end


    --[[
    --[[
    Line 1,018: Line 1,159:
    end
    end
    -- if necessary wrap result in <span> tag to format in Small Caps
    if ( "scap" == format ) then -- apply smallcaps formatting when authorformat or editorformat set to scap
    if ( "scap" == format ) then result =  
    result = substitute (cfg.presentation['smallcaps'], result);
    '<span class="smallcaps" style="font-variant:small-caps">' .. result .. '</span>';
    end  
    end  
    return result, count
    return result, count
    Line 1,088: Line 1,228:
    end
    end


    -- Takes a table of IDs and turns it into a table of formatted ID outputs.
    --[[--------------------------< B U I L D I D L I S T >--------------------------------------------------------
    Takes a table of IDs and turns it into a table of formatted ID outputs.
     
    ]]
    function buildidlist( id_list, options )
    function buildidlist( id_list, options )
    local new_list, handler = {};
    local new_list, handler = {};
     
    function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end;
    function fallback(k) return { __index = function(t,i) return cfg.id_handlers[k][i] end } end;
    Line 1,126: Line 1,269:
    end
    end
    table.insert( new_list, {handler.label, ISBN } );
    table.insert( new_list, {handler.label, ISBN } );
    elseif k == 'USENETID' then
    table.insert( new_list, {handler.label, message_id( v ) } );
    else
    else
    error( cfg.messages['unknown_manual_ID'] );
    error( cfg.messages['unknown_manual_ID'] );
    Line 1,185: Line 1,330:
    for _, k in ipairs( error_list ) do
    for _, k in ipairs( error_list ) do
    if error_str ~= "" then error_str = error_str .. cfg.messages['parameter-separator'] end
    if error_str ~= "" then error_str = error_str .. cfg.messages['parameter-separator'] end
    error_str = error_str .. wrap( 'parameter', k );
    error_str = error_str .. wrap_style ('parameter', k);
    end
    end
    if #error_list > 1 then
    if #error_list > 1 then
    Line 1,192: Line 1,337:
    error_str = error_str .. cfg.messages['parameter-pair-separator'];
    error_str = error_str .. cfg.messages['parameter-pair-separator'];
    end
    end
    error_str = error_str .. wrap( 'parameter', selected );
    error_str = error_str .. wrap_style ('parameter', selected);
    table.insert( z.message_tail, { seterror( error_condition, {error_str}, true ) } );
    table.insert( z.message_tail, { seterror( error_condition, {error_str}, true ) } );
    end
    end
    Line 1,220: Line 1,365:
    OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book";
    OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:book";
    OCinSoutput["rft.genre"] = "bookitem";
    OCinSoutput["rft.genre"] = "bookitem";
    OCinSoutput["rft.btitle"] = data.Chapter;
    OCinSoutput["rft.atitle"] = data.Chapter;
    OCinSoutput["rft.atitle"] = data.Title;
    OCinSoutput["rft.btitle"] = data.Title;
    elseif is_set(data.Periodical) then
    elseif is_set(data.Periodical) then
    OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";
    OCinSoutput.rft_val_fmt = "info:ofi/fmt:kev:mtx:journal";
    Line 1,334: Line 1,479:
    the page is a mainspace page and the ISO639-1 code is not 'en'.  Similarly, if the  parameter is |language=Norwegian, it will be categorized in the same way.
    the page is a mainspace page and the ISO639-1 code is not 'en'.  Similarly, if the  parameter is |language=Norwegian, it will be categorized in the same way.


    TODO: Error message when language or language code is not ISO639-1?
    ]]
    ]]


    Line 1,358: Line 1,502:
    if is_set (code) then
    if is_set (code) then
    if 'no' == code then name = 'Norwegian' end; -- override wikimedia when code is 'no'
    if 'no' == code then name = 'Norwegian' end; -- override wikimedia when code is 'no'
    if 0 == namespace and 'en' ~= code then -- is this page main / article space and English not the language?
    if 0 == namespace and 'en' ~= code then -- is this page main / article space and English not the language?
    table.insert( z.properties_cats, 'CS1 ' .. name .. '-language sources (' .. code .. ')'); -- in main space and not English: categorize
    table.insert( z.properties_cats, 'CS1 ' .. name .. '-language sources (' .. code .. ')'); -- in main space and not English: categorize
    end
    end
    end
    return (" " .. wrap( 'language', name)); -- wrap with '(in ...)'
    else
    table.insert (z.maintenance_cats, 'CS1 maint: Unrecognized language'); -- add maintenance category when |language= does not appear to be ISO 639-1 language
    end
    return (" " .. wrap_msg ('language', name)); -- wrap with '(in ...)'
    end
    end


    Line 1,409: Line 1,555:
    local TitleLink = A['TitleLink'];
    local TitleLink = A['TitleLink'];
    local Chapter = A['Chapter'];
    local Chapter = A['Chapter'];
    local ChapterLink = A['ChapterLink'];
    local ChapterLink = A['ChapterLink']; -- deprecated
    local TransChapter = A['TransChapter'];
    local TransChapter = A['TransChapter'];
    local TitleType = A['TitleType'];
    local TitleType = A['TitleType'];
    Line 1,445: Line 1,591:
    local Language = A['Language'];
    local Language = A['Language'];
    local Format = A['Format'];
    local Format = A['Format'];
    local ChapterFormat = A['ChapterFormat'];
    local Ref = A['Ref'];
    local Ref = A['Ref'];
    local DoiBroken = A['DoiBroken'];
    local DoiBroken = A['DoiBroken'];
    Line 1,453: Line 1,600:


    local ID_list = extractids( args );
    local ID_list = extractids( args );
    --[[ Hide unfinished cite newsgroup code so that long delayed update can take place
     
    -- special case for cite newsgroup which uses |id= for a usenet article or post id
    -- |id= is not included in COinS so here we convert it to an ID that will be included in COinS
    if ('newsgroup' == config.CitationClass) and (is_set (ID)) then
    ID_list['USENETID']=ID; -- add this new 'id' to the list of IDs
    ID = ''; -- and unset
    end
    ]]
    local Quote = A['Quote'];
    local Quote = A['Quote'];
    local PostScript = A['PostScript'];
    local PostScript = A['PostScript'];
    Line 1,477: Line 1,617:
    local Callsign = A['Callsign'];
    local Callsign = A['Callsign'];
    local City = A['City'];
    local City = A['City'];
    local Cointerviewers = A['Cointerviewers']; -- deprecated
    local Interviewer = A['Interviewer']; -- deprecated
    local Program = A['Program'];
    local Program = A['Program'];


    --local variables that are not cs1 parameters
    --local variables that are not cs1 parameters
    local page_type; -- is this needed?  Doesn't appear to be used anywhere;
    local use_lowercase; -- controls capitalization of certain static text
    local use_lowercase = ( sepc ~= '.' );
    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
    local anchor_year; -- used in the CITEREF identifier
    local anchor_year; -- used in the CITEREF identifier
    local COinS_date; -- used in the COinS metadata
    local COinS_date; -- used in the COinS metadata
    Line 1,535: Line 1,672:


    |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


    All other combinations of |encyclopedia, |title, and |article are not modified
    All other combinations of |encyclopedia, |title, and |article are not modified
    Line 1,544: Line 1,682:
    Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
    Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
    TransChapter = TransTitle;
    TransChapter = TransTitle;
    ChapterURL = URL;
    Title = Periodical;
    Title = Periodical;
    Periodical = ''; -- redundant so unset
    Periodical = ''; -- redundant so unset
    TransTitle = ''; -- redundant so unset
    TransTitle = ''; -- redundant so unset
    URL = ''; -- redundant so unset
    end
    end
    else -- |title not set
    else -- |title not set
    Line 1,568: Line 1,708:
    end
    end
    end
    end
    use_lowercase = ( sepc ~= '.' ); -- used to control capitalization for certain static text


    -- check for special case where |separator=none
    -- check for special case where |separator=none
    Line 1,606: Line 1,747:
    end
    end


    if is_set(Interviewer) then
    if is_set(Others) then
    if is_set(TitleType) then
    if is_set(TitleType) then
    Others = ' ' .. TitleType .. ' with ' .. Interviewer;
    Others = ' ' .. TitleType .. ' with ' .. Others;
    TitleType = '';
    TitleType = '';
    else
    else
    Others = ' ' .. 'Interview with ' .. Interviewer;
    Others = ' ' .. 'Interview with ' .. Others;
    end
    if is_set(Cointerviewers) then
    Others = Others .. sepc .. ' ' .. Cointerviewers;
    end
    end
    else
    else
    Line 1,671: Line 1,809:
    -- end of {{cite episode}} stuff]]
    -- end of {{cite episode}} stuff]]


    -- legacy: promote concatenation of |day=, |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set.
    -- legacy: promote concatenation of |month=, and |year= to Date if Date not set; or, promote PublicationDate to Date if neither Date nor Year are set.
    if not is_set(Date) then
    if is_set(Date) then
    if is_set (Year) then
    table.insert( z.maintenance_cats, "CS1 maint: Date and year"); -- add to maint category
    end
    else
    Date = Year; -- promote Year to Date
    Date = Year; -- promote Year to Date
    Year = nil; -- make nil so Year as empty string isn't used for CITEREF
    Year = nil; -- make nil so Year as empty string isn't used for CITEREF
    Line 1,679: Line 1,821:
    if is_set(Month) then
    if is_set(Month) then
    Date = Month .. " " .. Date;
    Date = Month .. " " .. Date;
    local Day = A['Day']
    if is_set(Day) then Date = Day .. " " .. Date end
    end
    end
    elseif is_set(PublicationDate) then -- use PublicationDate when |date= and |year= are not set
    elseif is_set(PublicationDate) then -- use PublicationDate when |date= and |year= are not set
    Line 1,735: Line 1,875:
    end
    end
    ]]
    ]]
    --[[ Hide unfinished cite newsgroup code so that long delayed update can take place
     
    -- special case for cite newsgroup.  Do this after COinS because we are modifying Publishername and ID
    -- special case for cite newsgroup.  Do this after COinS because we are modifying Publishername to include som static text
    if 'newsgroup' == config.CitationClass then
    if 'newsgroup' == config.CitationClass then
    if is_set (PublisherName) then
    if is_set (PublisherName) then
    PublisherName = '[Newsgroup]:&nbsp;' ..  externallink( 'news:' .. PublisherName, PublisherName );
    PublisherName = '[[Newsgroup]]:&nbsp;' ..  externallink( 'news:' .. PublisherName, PublisherName );
    end
    end
    end
    end
    ]]
     




    Line 1,750: Line 1,890:
    if not is_set(Authors) then
    if not is_set(Authors) then
    local Maximum = tonumber( A['DisplayAuthors'] );
    local Maximum = tonumber( A['DisplayAuthors'] );
     
    -- Preserve old-style implicit et al.
    if is_set (Maximum) then
    if not is_set(Maximum) and #a == 9 then  
    if Maximum >= #a then -- if display-authors value greater than or equal to number of authors
    Maximum = 8;
    table.insert( z.maintenance_cats, "CS1 maint: display-authors"); -- add maintenance category because display-authors parameter may be removed
    table.insert( z.message_tail, { seterror('implict_etal_author', {}, true ) } );
    end
    elseif not is_set(Maximum) then
    else
    Maximum = #a + 1;
    Maximum = #a + 1; -- number of authors + 1
    end
    end
     
    local control = {  
    local control = {  
    sep = A["AuthorSeparator"] .. " ",
    sep = A["AuthorSeparator"] .. " ",
    Line 1,798: Line 1,938:
    maximum = Maximum,
    maximum = Maximum,
    lastauthoramp = LastAuthorAmp,
    lastauthoramp = LastAuthorAmp,
    page_name = this_page.text -- get current page name so that we don't wikilink to it via authorlinkn
    page_name = this_page.text -- get current page name so that we don't wikilink to it via editorlinkn
    };
    };


    Line 1,815: Line 1,955:
    Cartography = A['Cartography'];
    Cartography = A['Cartography'];
    if is_set( Cartography ) then
    if is_set( Cartography ) then
    Cartography = sepc .. " " .. wrap( 'cartography', Cartography, use_lowercase );
    Cartography = sepc .. " " .. wrap_msg ('cartography', Cartography, use_lowercase);
    end
    end
    Scale = A['Scale'];
    Scale = A['Scale'];
    Line 1,823: Line 1,963:
    end
    end
    Format = is_set(Format) and " (" .. Format .. ")" or "";
    if  not is_set(URL) and
    if  not is_set(URL) and
    not is_set(ChapterURL) and
    not is_set(ArchiveURL) and
    not is_set(ArchiveURL) and
    not is_set(ConferenceURL) and
    not is_set(ConferenceURL) and
    Line 1,835: Line 1,976:
    -- Test if accessdate is given without giving a URL
    -- Test if accessdate is given without giving a URL
    if is_set(AccessDate) then
    if is_set(AccessDate) and not is_set(ChapterURL)then -- ChapterURL may be set when the others are not set; TODO: move this to a separate test?
    table.insert( z.message_tail, { seterror( 'accessdate_missing_url', {}, true ) } );
    table.insert( z.message_tail, { seterror( 'accessdate_missing_url', {}, true ) } );
    AccessDate = '';
    AccessDate = '';
    Line 1,842: Line 1,983:
    -- Test if format is given without giving a URL
    -- Test if format is given without giving a URL
    if is_set(Format) then
    if is_set(Format) then
    Format = Format .. seterror( 'format_missing_url' );
    Format = Format .. seterror( 'format_missing_url', {'format', 'url'} );
    end
    end
    end
    end
     
    -- 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 1,855: Line 1,996:
    end
    end
    Format = is_set(Format) and " (" .. Format .. ")" or "";
     
    local OriginalURL;
    local OriginalURL = URL
    DeadURL = DeadURL:lower(); -- used later when assembling archived text
    DeadURL = DeadURL:lower();
    if is_set( ArchiveURL ) then
    if is_set( ArchiveURL ) then
    if ( DeadURL ~= "no" ) then
    if is_set (URL) then
    URL = ArchiveURL
    OriginalURL = URL; -- save copy of original source URL
    URLorigin = A:ORIGIN('ArchiveURL')
    if 'no' ~= DeadURL then -- if URL set then archive-url applies to it
    URL = ArchiveURL -- swap-in the archive's url
    URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
    end
    elseif is_set (ChapterURL) then -- URL not set so if chapter-url is set apply archive url to it
    OriginalURL = ChapterURL; -- save copy of source chapter's url for archive text
    if 'no' ~= DeadURL then
    ChapterURL = ArchiveURL -- swap-in the archive's url
    URLorigin = A:ORIGIN('ArchiveURL') -- name of archive url parameter for error messages
    end
    end
    end
    end
    -- Format chapter / article title
    if is_set(Chapter) and is_set(ChapterLink) then
    Chapter = "[[" .. ChapterLink .. "|" .. Chapter .. "]]";
    end
    end


    Chapter = kern_quotes (Chapter); -- if necessary, separate chapter title's leading and trailing quote marks from Module provided quote marks
    if inArray(config.CitationClass, {"web","news","journal","pressrelease","conference","podcast", "newsgroup"}) or ('citation' == config.CitationClass and is_set (Periodical)) then
    Chapter = wrap( 'quoted-title', Chapter );
    if is_set (Chapter) or is_set (TransChapter) or is_set (ChapterURL)then -- chapter parameters not supported for these citation types
    TransChapter = wrap( 'trans-quoted-title', TransChapter );
    table.insert( z.message_tail, { seterror( 'chapter_ignored', {}, true ) } ); -- add error message
     
    Chapter = ''; -- set to empty string to be safe with concatenation
    local TransError = ""
    TransChapter = '';
    if is_set(TransChapter) then
    ChapterURL = '';
    if not is_set(Chapter) then
    end
    TransError = " " .. seterror( 'trans_missing_chapter' ); -- add error message
    else -- otherwise, format chapter / article title
    else
    Chapter = format_chapter_title (Chapter, TransChapter, ChapterURL, ChapterURLorigin);
    TransChapter = " " .. TransChapter;
    if is_set (Chapter) then
    ChapterFormat = is_set(ChapterFormat) and " (" .. ChapterFormat .. ")" or "";
    if is_set(ChapterFormat) and not is_set (ChapterURL) then -- Test if |chapter-format= is given without giving a |chapter-url=
    ChapterFormat = ChapterFormat .. seterror( 'format_missing_url', {'chapter-format', 'chapter-url'} );
    end
    Chapter = Chapter .. ChapterFormat .. sepc .. ' ';
    end
    end
    end
    end
     
    Chapter = Chapter .. TransChapter;
    if is_set(Chapter) then
    if not is_set(ChapterLink) then
    if is_set(ChapterURL) then
    Chapter = externallink( ChapterURL, Chapter ) .. TransError;
    if not is_set(URL) then
    Chapter = Chapter .. Format;
    Format = "";
    end
    elseif is_set(URL) then
    Chapter = externallink( URL, Chapter ) .. TransError .. Format;
    URL = "";
    Format = "";
    else
    Chapter = Chapter .. TransError;
    end
    elseif is_set(ChapterURL) then
    Chapter = Chapter .. " " .. externallink( ChapterURL, nil, ChapterURLorigin ) .. TransError; -- ChapterURLorigin holds the name of parameter
    else
    Chapter = Chapter .. TransError;
    end
    Chapter = Chapter .. sepc .. " " -- with end-space
    elseif is_set(ChapterURL) then
    Chapter = " " .. externallink( ChapterURL, nil, ChapterURLorigin ) .. sepc .. " ";
    end
    -- Format main title.
    -- Format main title.
    if is_set(TitleLink) and is_set(Title) then
    if is_set(TitleLink) and is_set(Title) then
    Line 1,916: Line 2,038:
    end
    end


    if inArray(config.CitationClass, {"web","news","journal","pressrelease","conference","podcast"}) then
    if inArray(config.CitationClass, {"web","news","journal","pressrelease","conference","podcast", "newsgroup"}) or ('citation' == config.CitationClass and is_set (Periodical)) then
    Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks
    Title = kern_quotes (Title); -- if necessary, separate title's leading and trailing quote marks from Module provided quote marks
    Title = wrap( 'quoted-title', Title );
    Title = wrap_style ('quoted-title', Title);
     
    Title = script_concatenate (Title, ScriptTitle); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped
    Title = script_concatenate (Title, ScriptTitle); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped
    TransTitle = wrap( 'trans-quoted-title', TransTitle );
    TransTitle= wrap_style ('trans-quoted-title', TransTitle );
    -- Chapter = ''; -- chapter not allowed - disabled because doing this here doesn't display error msg and promoted url is lost
    else
    else
    Title = wrap( 'italic-title', Title );
    Title = wrap_style ('italic-title', Title);
    Title = script_concatenate (Title, ScriptTitle); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped
    Title = script_concatenate (Title, ScriptTitle); -- <bdi> tags, lang atribute, categorization, etc; must be done after title is wrapped
    TransTitle = wrap( 'trans-italic-title', TransTitle );
    TransTitle = wrap_style ('trans-italic-title', TransTitle);
    end
    end


    Line 1,950: Line 2,072:


    if is_set(Place) then
    if is_set(Place) then
    Place = " " .. wrap( 'written', Place, use_lowercase ) .. sepc .. " ";
    Place = " " .. wrap_msg ('written', Place, use_lowercase) .. sepc .. " ";
    end
    end
    Line 2,011: Line 2,133:
    if first_set( Pages, Page, At ) ~= nil or sepc ~= '.' then
    if first_set( Pages, Page, At ) ~= nil or sepc ~= '.' then
    if is_set( Section ) then
    if is_set( Section ) then
    Section = ", " .. wrap( 'section', Section, true );
    Section = ", " .. wrap_msg ('section', Section, true);
    end
    end
    if is_set( Inset ) then
    if is_set( Inset ) then
    Inset = ", " .. wrap( 'inset', Inset, true );
    Inset = ", " .. wrap_msg ('inset', Inset, true);
    end
    end
    else
    else
    if is_set( Section ) then
    if is_set( Section ) then
    Section = sepc .. " " .. wrap( 'section', Section, use_lowercase );
    Section = sepc .. " " .. wrap_msg ('section', Section, use_lowercase);
    if is_set( Inset ) then
    if is_set( Inset ) then
    Inset = ", " .. wrap( 'inset', Inset, true );
    Inset = ", " .. wrap_msg ('inset', Inset, true);
    end
    end
    elseif is_set( Inset ) then
    elseif is_set( Inset ) then
    Inset = sepc .. " " .. wrap( 'inset', Inset, use_lowercase );
    Inset = sepc .. " " .. wrap_msg ('inset', Inset, use_lowercase);
    end
    end
    end
    end
    Line 2,051: Line 2,173:


    TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
    TitleNote = is_set(TitleNote) and (sepc .. " " .. TitleNote) or "";
    Edition = is_set(Edition) and (" " .. wrap( 'edition', Edition )) or "";
    Edition = is_set(Edition) and (" " .. wrap_msg ('edition', Edition)) or "";
    Issue = is_set(Issue) and (" (" .. Issue .. ")") or "";
    Issue = is_set(Issue) and (" (" .. Issue .. ")") or "";
    Series = is_set(Series) and (sepc .. " " .. Series) or "";
    Series = is_set(Series) and (sepc .. " " .. Series) or "";
    Line 2,064: Line 2,186:
    end
    end


    --[[ This code commented out while discussion continues until after week of 2014-03-23 live module update;
    if is_set(Volume) then
    if ( mw.ustring.len(Volume) > 4 )
      then Volume = sepc .. " " .. Volume;
      else
      Volume = " <b>" .. hyphentodash(Volume) .. "</b>";
      if is_set(Series) then Volume = sepc .. Volume;
      end
    end
    end
    ]]
    ------------------------------------ totally unrelated data
    ------------------------------------ totally unrelated data
    --[[ Loosely mimic {{subscription required}} template; Via parameter identifies a delivery source that is not the publisher; these sources often, but not always, exist
    behind a registration or paywall.  So here, we've chosen to decouple via from subscription (via has never been part of the registration required template).
    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.
    ]]
    if is_set(Via) then
    if is_set(Via) then
    Via = " " .. wrap( 'via', Via );
    Via = " " .. wrap_msg ('via', Via);
    end
    end


    --[[
    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.
    ]]
    if is_set(SubscriptionRequired) then
    if is_set(SubscriptionRequired) then
    SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; --here when 'via' parameter not used but 'subscription' is
    SubscriptionRequired = sepc .. " " .. cfg.messages['subscription']; -- subscription required message
    elseif is_set(RegistrationRequired) then
    elseif is_set(RegistrationRequired) then
    SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; --here when 'via' and 'subscription' parameters not used but 'registration' is
    SubscriptionRequired = sepc .. " " .. cfg.messages['registration']; -- registration required message
    end
    end


    if is_set(AccessDate) then
    if is_set(AccessDate) then
    local retrv_text = " " .. cfg.messages['retrieved']
    local retrv_text = " " .. cfg.messages['retrieved']
    if (sepc ~= ".") then retrv_text = retrv_text:lower() end
     
    AccessDate = '<span class="reference-accessdate">' .. sepc
    AccessDate = nowrap_date (AccessDate); -- wrap in nowrap span if date in appropriate format
    .. substitute( retrv_text, {AccessDate} ) .. '</span>'
    if (sepc ~= ".") then retrv_text = retrv_text:lower() end -- if 'citation', lower case
    AccessDate = substitute (retrv_text, AccessDate); -- add retrieved text
    -- neither of these work; don't know why; it seems that substitute() isn't being called
    AccessDate = substitute (cfg.presentation['accessdate'], {sepc, AccessDate}); -- allow editors to hide accessdates
    end
    end
    Line 2,103: Line 2,217:
    end
    end


    ID_list = buildidlist( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo} );
    ID_list = buildidlist( ID_list, {DoiBroken = DoiBroken, ASINTLD = ASINTLD, IgnoreISBN = IgnoreISBN, Embargo=Embargo} );


    Line 2,114: Line 2,227:
    Quote = Quote:sub(2,-2);
    Quote = Quote:sub(2,-2);
    end
    end
    Quote = sepc .." " .. wrap( 'quoted-text', Quote );  
    Quote = sepc .." " .. wrap_style ('quoted-text', Quote ); -- wrap in <q>...</q> tags
    PostScript = ""; -- CS1 does not supply terminal punctuation when |quote= is set
    PostScript = ""; -- CS1 does not supply terminal punctuation when |quote= is set
    end
    end
    Line 2,185: Line 2,298:
    if is_set(PublicationDate) then
    if is_set(PublicationDate) then
    if is_set(Publisher) then
    if is_set(Publisher) then
    Publisher = Publisher .. ", " .. wrap( 'published', PublicationDate );
    Publisher = Publisher .. ", " .. wrap_msg ('published', PublicationDate);
    else
    else
    Publisher = PublicationDate;
    Publisher = PublicationDate;
    Line 2,195: Line 2,308:
    else
    else
    if is_set(PublicationDate) then
    if is_set(PublicationDate) then
    PublicationDate = " (" .. wrap( 'published', PublicationDate ) .. ")";
    PublicationDate = " (" .. wrap_msg ('published', PublicationDate) .. ")";
    end
    end
    if is_set(PublisherName) then
    if is_set(PublisherName) then
    Line 2,213: Line 2,326:
    if is_set(Periodical) then
    if is_set(Periodical) then
    if is_set(Title) or is_set(TitleNote) then  
    if is_set(Title) or is_set(TitleNote) then  
    Periodical = sepc .. " " .. wrap( 'italic-title', Periodical )  
    Periodical = sepc .. " " .. wrap_style ('italic-title', Periodical)  
    else  
    else  
    Periodical = wrap( 'italic-title', Periodical )
    Periodical = wrap_style ('italic-title', Periodical)
    end
    end
    end
    end