Module:Citation/CS1: Difference between revisions

    m>Trappist the monk
    (Fix sandbox oversight;)
    m>Trappist the monk
    (Sync from sandbox; Bug fixes; streamlined deprecated parameter detection; Year and PublicationDate promotion to Date consolidation; Change pmc/url handling; Modify parameter handling for cite encyclopedia;)
    Line 1: Line 1:
    --[[
    History of changes since last sync 2013-11-09
    2013-11-13: Fix Script Error bug that occured when |doi_brokendate= did not contain a year value;
    2013-11-13: Fix doi() so that dois with invalid doi_brokendate categorize to "Pages with inactive DOIs" and not to "Pages with DOIs inactive since";
    2013-11-14: Change deprecated_parameter() to emit a single error message;
    2013-11-15: Fix bug in checkisbn() that stripped-out non-isbn character before validation; declared good as long as the stripped version of the isbn passed the remaining tests;
    2013-11-21: Year and PublicationDate promotion to Date consolidation;
    2013-11-22: Change validate() and the whitelist to recognize deprecated parameters;
    2013-11-30: Change pmc/url handling;
    2013-12-05: Modify |encyclopedia, |title and |article parameter handling for cite encyclopedia;
    ]]
    local z = {
    local z = {
         error_categories = {};
         error_categories = {};
    Line 39: Line 52:
    end
    end


    -- Add this page to the deprecated parameter tracking category
    --[[
    Categorize and emit an error message when the citation contains one or more deprecated parameters.  Because deprecated parameters (currently |day=, |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)
    details of which parameter caused the error message are not provided.  Only one error message is emitted regarless of the number of deprecated parameters in the citation.
    ]]
    function deprecated_parameter()
    function deprecated_parameter()
    if true ~= Page_in_deprecated_cat then -- if we haven't been here before then set a  
    if true ~= Page_in_deprecated_cat then -- if we haven't been here before then set a  
    Page_in_deprecated_cat=true; -- sticky flag so that if there are more than one deprecated parameter the category is added only once
    Page_in_deprecated_cat=true; -- sticky flag so that if there are more than one deprecated parameter the category is added only once
    table.insert( z.error_categories, "Pages containing cite templates with deprecated parameters" ); -- add page to category
    table.insert( z.message_tail, { seterror( 'deprecated_params', {error_message}, true ) } ); -- add error message
    end
    end
    end
    end
    Line 113: Line 130:
    end
    end


    -- Checks that parameter name is valid using the whitelist
    --[[
    Looks for a parameter's name in the whitelist.
     
    Parameters in the whitelist can have three valuse:
    true - active, supported parameters
    false - deprecated, supported parameters
    nil - unsupported parameters
    ]]
    function validate( name )
    function validate( name )
        name = tostring( name );
    local name = tostring( name );
       
    local state = whitelist.basic_arguments[ name ];
        -- Normal arguments
        if whitelist.basic_arguments[ name ] then
    -- Normal arguments
            return true;
    if true == state then return true; end -- valid actively supported parameter
        end
    if false == state then
       
    deprecated_parameter (); -- parameter is deprecated but still supported
        -- Arguments with numbers in them
    return true;
        name = name:gsub( "%d+", "#" );
    end
        if whitelist.numbered_arguments[ name ] then
            return true;
    -- Arguments with numbers in them
        end
    name = name:gsub( "%d+", "#" ); -- replace digit(s) with # (last25 becomes last#
       
    state = whitelist.numbered_arguments[ name ];
        -- Not found, argument not supported.
    if true == state then return true; end -- valid actively supported parameter
        return false
    if false == state then
    deprecated_parameter (); -- parameter is deprecated but still supported
    return true;
    end
    return false; -- Not supported because not found or name is set to nil
    end
    end


    Line 227: Line 256:


    --[[
    --[[
    Formats a PMC and checks for embargoed articles. The embargo parameter takes a date for a value. If the embargo date is in the futue
    Determines if a PMC identifier's online version is embargoed. Compares the date in |embargo= against today's date. If embargo date is
    the PMC identifier will not be linked to the article.  If the embargo specifies a date in the past, or if it is empty or omitted, then
    in the future, returns true; otherwse, returns false because the embargo has expired or |embargo= not set in this cite.
    the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].link.
     
    The {{citation/core}} version of {{cite journal}} links the citation title (if url parameter is empty) when embargo date is in the past
    or when embargo parameter is missing or empty. That behavior is inconsistent with the behavior of other identifiers used in CS1 and is
    not supported here.
    ]]
    ]]
    function pmc(id, embargo)
    function is_embargoed(embargo)
    local handler = cfg.id_handlers['PMC'];
       
    local text;
    if is_set(embargo) then
    if is_set(embargo) then
    local lang = mw.getContentLanguage();
    local lang = mw.getContentLanguage();
    Line 245: Line 265:
    good1, embargo_date = pcall( lang.formatDate, lang, 'U', embargo );
    good1, embargo_date = pcall( lang.formatDate, lang, 'U', embargo );
    good2, todays_date = pcall( lang.formatDate, lang, 'U' );
    good2, todays_date = pcall( lang.formatDate, lang, 'U' );
    if good1 and good2 and tonumber( embargo_date ) >= tonumber( todays_date ) then --is embargo date is in the future?
    return true; -- still embargoed
    end
    end
    return false; -- embargo expired or |embargo= not set
    end


    if good1 and good2 and tonumber( embargo_date ) < tonumber( todays_date ) then --if embargo date is in the past then
    --[[
    text = externallinkid({link = handler.link, label = handler.label, --ok to link to article
    Formats a PMC and checks for embargoed articles.  The embargo parameter takes a date for a value. If the embargo date is in the future
    prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
    the PMC identifier will not be linked to the article.  If the embargo specifies a date in the past, or if it is empty or omitted, then
    else
    the PMC identifier is linked to the article through the link at cfg.id_handlers['PMC'].prefix.
    text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id; --still embargoed so no external link
    ]]
    end
    function pmc(id, embargo)
    local handler = cfg.id_handlers['PMC'];
       
    local text;
     
    if is_embargoed(embargo) then
    text="[[" .. handler.link .. "|" .. handler.label .. "]]:" .. handler.separator .. id; --still embargoed so no external link
    else
    else
    text = externallinkid({link = handler.link, label = handler.label, --no embargo date, ok to link to article
    text = externallinkid({link = handler.link, label = handler.label, --no embargo date, ok to link to article
    prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
    prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
    end
    end
    return text
    return text;
    end
    end


    Line 265: Line 298:
          
          
         local text;
         local text;
        if is_set(inactive) then
    if is_set(inactive) then
            text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
    local inactive_year = inactive:match("%d%d%d%d") or ''; -- try to get the year portion from the inactive date
            table.insert( z.error_categories, "Pages with DOIs inactive since " .. selectyear(inactive) );      
    text = "[[" .. handler.link .. "|" .. handler.label .. "]]:" .. id;
            inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"  
    if is_set(inactive_year) then
        else  
    table.insert( z.error_categories, "Pages with DOIs inactive since " .. inactive_year );
            text = externallinkid({link = handler.link, label = handler.label,
    else
                prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
    table.insert( z.error_categories, "Pages with inactive DOIs" ); -- when inactive doesn't contain a recognizable year
            inactive = ""  
    end
        end
    inactive = " (" .. cfg.messages['inactive'] .. " " .. inactive .. ")"  
        if ( string.sub(id,1,3) ~= "10." ) then       
    else  
            cat = seterror( 'bad_doi' );
    text = externallinkid({link = handler.link, label = handler.label,
        end
    prefix=handler.prefix,id=id,separator=handler.separator, encode=handler.encode})
        return text .. inactive .. cat  
    inactive = ""  
    end
    if ( string.sub(id,1,3) ~= "10." ) then       
    cat = seterror( 'bad_doi' );
    end
    return text .. inactive .. cat  
    end
    end


    Line 344: Line 382:
    end
    end


    -- returns a number according to the month in a date 1 for January, etc.  If not a valid month, returns 0
    --[[
    function get_month_number (month)
    This function sets default title types (equivalent to the citation including |type=<default value>) for those citations that have defaults.
    local long_months = {['january']=1, ['february']=2, ['march']=3, ['april']=4, ['may']=5, ['june']=6, ['july']=7, ['august']=8, ['september']=9, ['october']=10, ['november']=11, ['december']=12};
    Also handles the special case where it is desireable to omit the title type from the rendered citation (|type=none).
    local short_months = {['jan']=1, ['feb']=2, ['mar']=3, ['apr']=4, ['may']=5, ['jun']=6, ['jul']=7, ['aug']=8, ['sep']=9, ['oct']=10, ['nov']=11, ['dec']=12};
    ]]
    function set_titletype(cite_class, title_type)
    if is_set(title_type) then
    if "none" == title_type then
    title_type = ""; -- if |type=none then type parameter not displayed
    end
    return title_type; -- if |type= has been set to any other value use that value
    end
     
    if "pressrelease" == cite_class then -- if this citation is cite press release
    return "Press release"; -- display press release annotation
     
    elseif "speech" == cite_class then -- if this citation is cite speech
    return "Speech"; -- display speech annotation
    elseif "techreport" == cite_class then -- if this citation is cite techreport
    return "Technical report"; -- display techreport annotation
    elseif "thesis" == cite_class then -- if this citation is cite thesis (degree option handled after this function returns)
    return "Thesis"; -- display simple thesis annotation (without |degree= modification)
    end
    end
     
    -- returns a number according to the month in a date: 1 for January, etc.  If not a valid month, returns 0
    function get_month_number (month)
    local long_months = {['january']=1, ['february']=2, ['march']=3, ['april']=4, ['may']=5, ['june']=6, ['july']=7, ['august']=8, ['september']=9, ['october']=10, ['november']=11, ['december']=12};
    local short_months = {['jan']=1, ['feb']=2, ['mar']=3, ['apr']=4, ['may']=5, ['jun']=6, ['jul']=7, ['aug']=8, ['sep']=9, ['oct']=10, ['nov']=11, ['dec']=12};
    local temp;
    local temp;
    temp=long_months[month:lower()];
    temp=long_months[month:lower()];
    if temp then return temp; end -- if month is the long-form name
    if temp then return temp; end -- if month is the long-form name
    temp=short_months[month:lower()];
    temp=short_months[month:lower()];
    if temp then return temp; end -- if month is the short-form name
    if temp then return temp; end -- if month is the short-form name
    return 0; -- misspelled or not a month name
    return 0; -- misspelled or not a month name
    end
    end


    Line 373: Line 437:
    local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    local days_in_month = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    local month_length;
    local month_length;
    if (2==month) then -- if February
    if (2==month) then -- if February
    month_length = 28; -- then 28 days unless
    month_length = 28; -- then 28 days unless
    if 1582 > tonumber(year) then -- Julian calendar
    if 1582 > tonumber(year) then -- Julian calendar
    if 0==(year%4) then
    if 0==(year%4) then
    month_length = 29;
    month_length = 29;
    end
    end
    else -- Gregorian calendar
    else -- Gregorian calendar
    if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- date specifies a leap year
    if (0==(year%4) and (0~=(year%100) or 0==(year%400))) then -- is a leap year?
    month_length = 29; -- if leap year then 29 days in February
    month_length = 29; -- if leap year then 29 days in February
    end
    end
    end
    end
    Line 395: Line 459:


    --Check a pair of months or seasons to see if both are valid members of a month or season pair.
    --Check a pair of months or seasons to see if both are valid members of a month or season pair.
    --TODO: Check order to make sure that the left month/season properly precedes the right month/season


    function is_valid_month_season_range(range_start, range_end)
    function is_valid_month_season_range(range_start, range_end)
    Line 408: Line 473:
    return true;
    return true;
    end
    end


    --[[
    --[[
    Line 425: Line 489:
    true, anchor_year, COinS_date
    true, anchor_year, COinS_date
    anchor_year can be used in CITEREF anchors
    anchor_year can be used in CITEREF anchors
    COinS_date is date_string without anchor_year disambiguators if any
    COinS_date is date_string without anchor_year disambiguator if any
    ]]
    ]]
    function check_date (date_string)
    function check_date (date_string)
    Line 463: Line 527:
    end
    end
    elseif date_string:match("^%a+%s*%d%d%d%d%a?$") then -- month/season year
    elseif date_string:match("^%a+%s*%d%d%d%d%a?$") then -- month/season year
    coins_date = date_string:match("%a+%s*%d%d%d%d");
    coins_date = date_string:match("%a+%s*%d%d%d%d");
    month, anchor_year, year=string.match(date_string, "(%a+)%s*((%d%d%d%d)%a?)");
    month, anchor_year, year=string.match(date_string, "(%a+)%s*((%d%d%d%d)%a?)");
    Line 510: Line 574:
    for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list
    for k, v in pairs(date_parameters_list) do -- for each date-holding parameter in the list
    if is_set(v) then -- if the parameter has a value
    if is_set(v) then -- if the parameter has a value
    if v:match("^c%.%s%d%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
    if v:match("^c%.%s%d%d%d%d?%a?$") then -- special case for c. year or with or without CITEREF disambiguator - only |date= and |year=
    if 'date'==k then
    if 'date'==k then
    good_date, anchor_year, COinS_date = true, v:match("((c%.%s%d%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
    good_date, anchor_year, COinS_date = true, v:match("((c%.%s%d%d%d%d?)%a?)"); -- anchor year and COinS_date only from |date= parameter
    Line 520: Line 584:
    good_date =  true;
    good_date =  true;
    end
    end
    elseif 'date'==k then -- if the parameter is |date=
    elseif 'date'==k then -- if the parameter is |date=
    if v:match("n%.d%.%a?") then -- if |date=n.d. with or without a CITEREF disambiguator
    if v:match("n%.d%.%a?") then -- if |date=n.d. with or without a CITEREF disambiguator
    good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; -- no error when date parameter is set to no date
    good_date, anchor_year, COinS_date = true, v:match("((n%.d%.)%a?)"); --"n.d."; no error when date parameter is set to no date
    elseif v:match("nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator
    elseif v:match("nd%a?$") then -- if |date=nd with or without a CITEREF disambiguator
    good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; -- no error when date parameter is set to no date
    good_date, anchor_year, COinS_date = true, v:match("((nd)%a?)"); --"nd"; no error when date parameter is set to no date
    else
    else
    good_date, anchor_year, COinS_date = check_date (v); -- go test the date
    good_date, anchor_year, COinS_date = check_date (v); -- go test the date
    Line 531: Line 595:
    good_date = check_date (v); -- go test the date
    good_date = check_date (v); -- go test the date
    end
    end
    if false==good_date then -- assemble one error message so we don't add the tracking category multiple times
    if false==good_date then -- assemble one error message so we don't add the tracking category multiple times
    if is_set(error_message) then -- once we've added the first portion of the error message ...
    if is_set(error_message) then -- once we've added the first portion of the error message ...
    error_message=error_message .. ", "; -- ... add a comma space separator
    error_message=error_message .. ", "; -- ... add a comma space separator
    Line 547: Line 611:


    --[[
    --[[
    Determines whether an URL string is valid
    Determines whether a URL string is valid


    At present the only check is whether the string appears to  
    At present the only check is whether the string appears to  
    Line 566: Line 630:


    --[[
    --[[
    ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. If the number is valid the result will be 0.
    ISBN-10 and ISSN validator code calculates checksum across all isbn/issn digits including the check digit. ISBN-13 is checked in checkisbn().
    Before calling this function, issbn/issn must be checked for length and stripped of dashes, spaces and other non-isxn characters.
    If the number is valid the result will be 0. Before calling this function, issbn/issn must be checked for length and stripped of dashes,
    spaces and other non-isxn characters.
    ]]
    ]]
    function is_valid_isxn (isxn_str, len)
    function is_valid_isxn (isxn_str, len)
    Line 573: Line 638:
    isxn_str = { isxn_str:byte(1, len) }; -- make a table of bytes
    isxn_str = { isxn_str:byte(1, len) }; -- make a table of bytes
    len = len+1; -- adjust to be a loop counter
    len = len+1; -- adjust to be a loop counter
    for i, v in ipairs( isxn_str ) do -- loop through all of the byte an calculate the checksum
    for i, v in ipairs( isxn_str ) do -- loop through all of the bytes and calculate the checksum
    if v == string.byte( "X" ) then -- if checkdigit is X
    if v == string.byte( "X" ) then -- if checkdigit is X
    temp = temp + 10*( len - i ); -- it represents 10 decimal
    temp = temp + 10*( len - i ); -- it represents 10 decimal
    Line 585: Line 650:
    -- Determines whether an ISBN string is valid
    -- Determines whether an ISBN string is valid
    function checkisbn( isbn_str )
    function checkisbn( isbn_str )
        isbn_str = cleanisbn( isbn_str ):gsub( "-", "" );
    if nil ~= isbn_str:match("[^%s-0-9X]") then return false; end -- fail if isbn_str contains anything but digits, hyphens, or the uppercase X
        local len = isbn_str:len();
    isbn_str = isbn_str:gsub( "-", "" ):gsub( " ", "" ); -- remove hyphens and spaces
    local len = isbn_str:len();
       
       
        if len ~= 10 and len ~= 13 then
    if len ~= 10 and len ~= 13 then
            return false;
    return false;
        end
    end
     
        if len == 10 then
    if len == 10 then
            if isbn_str:match( "^%d*X?$" ) == nil then return false; end
    if isbn_str:match( "^%d*X?$" ) == nil then return false; end
    return is_valid_isxn(isbn_str, 10);
    return is_valid_isxn(isbn_str, 10);
        else
    else
        local temp = 0;
    local temp = 0;
            if isbn_str:match( "^97[89]%d*$" ) == nil then return false; end -- isbn13 begins with 978 or 979
    if isbn_str:match( "^97[89]%d*$" ) == nil then return false; end -- isbn13 begins with 978 or 979
            isbn_str = { isbn_str:byte(1, len) };
    isbn_str = { isbn_str:byte(1, len) };
            for i, v in ipairs( isbn_str ) do
    for i, v in ipairs( isbn_str ) do
                temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );
    temp = temp + (3 - 2*(i % 2)) * tonumber( string.char(v) );
            end
    end
            return temp % 10 == 0;
    return temp % 10 == 0;
        end
    end
    end
    end


    Line 724: Line 790:
    end   
    end   


    --[[
    -- Attempts to convert names to initials.
    Return the year portion of a date string, if possible. 
    function reducetoinitials(first)
    Returns empty string if the argument can not be interpreted
         local initials = {}
    as a year.
     
    BUG: If editors set |date=n.d or |date=n.da then selectyear() returns the current year for use in CITEREF.  These "dates" are caught by dates().
    ]]
    function selectyear( str )
    -- Is the input a simple number?
    local num = tonumber( str );
    if num ~= nil and num > 0 and num < 2100 and num == math.floor(num) then
    return str;
    else
    -- Use formatDate to interpret more complicated formats
    local lang = mw.getContentLanguage();
    local good, result;
    good, result = pcall( lang.formatDate, lang, 'Y', str );
    if good then return result; end -- if good
    end
    end
     
    -- Attempts to convert names to initials.
    function reducetoinitials(first)
         local initials = {}
         for word in string.gmatch(first, "%S+") do
         for word in string.gmatch(first, "%S+") do
             table.insert(initials, string.sub(word,1,1)) -- Vancouver format does not include full stops.
             table.insert(initials, string.sub(word,1,1)) -- Vancouver format does not include full stops.
    Line 893: Line 938:
         end
         end
          
          
         function comp( a, b )
         function comp( a, b ) -- used in following table.sort()
             return a[1] < b[1];
             return a[1] < b[1];
         end
         end
    Line 1,043: Line 1,088:


    --[[
    --[[
    This is the main function foing the majority of the citation
    This is the main function doing the majority of the citation
    formatting.
    formatting.
    ]]
    ]]
    Line 1,095: Line 1,140:
         local ConferenceURLorigin = A:ORIGIN('ConferenceURL');
         local ConferenceURLorigin = A:ORIGIN('ConferenceURL');
         local Periodical = A['Periodical'];
         local Periodical = A['Periodical'];
       
        if ( config.CitationClass == "encyclopaedia" ) then
            if not is_set(Chapter) then
                if not is_set(Title) then
                    Title = Periodical;
                    Periodical = '';
                else
                    Chapter = Title
                    TransChapter = TransTitle
                    Title = '';
                    TransTitle = '';
                end
            end
        end


        local Series = A['Series'];
    --[[
    Parameter remapping for cite encyclopedia:
    When the citation has these parameters:
    |encyclopedia and |title then map |title to |article and |encyclopedia to |title
    |encyclopedia and |article then map |encyclopedia to |title
    |encyclopedia then map |encyclopedia to |title
     
    |trans_title maps to |trans_chapter when |title is re-mapped
     
    All other combinations of |encyclopedia, |title, and |article are not modified
    ]]
    if ( config.CitationClass == "encyclopaedia" ) then
    if is_set(Periodical) then -- Periodical is set when |encyclopedia is set
    if is_set(Title) then
    if not is_set(Chapter) then
    Chapter = Title; -- |encyclopedia and |title are set so map |title to |article and |encyclopedia to |title
    TransChapter = TransTitle;
    Title = Periodical;
    Periodical = ''; -- redundant so unset
    TransTitle = ''; -- redundant so unset
    end
    else -- |title not set
    Title = Periodical; -- |encyclopedia set and |article set or not set so map |encyclopedia to |title
    Periodical = ''; -- redundant so unset
    end
    end
    end
     
    local Series = A['Series'];
         local Volume = A['Volume'];
         local Volume = A['Volume'];
         local Issue = A['Issue'];
         local Issue = A['Issue'];
    Line 1,160: Line 1,219:
    local ID = A['ID'];
    local ID = A['ID'];
    if (config.CitationClass == "techreport") then -- special case for cite techreport
    if (config.CitationClass == "techreport") then -- special case for cite techreport
    if is_set(Issue) then -- cite techreport uses 'number', which everything else aliases to 'issue'
    if is_set(Issue) then -- cite techreport uses 'number', which other citations aliase to 'issue'
    if not is_set(ID) then -- can we use ID for the "number"?
    if not is_set(ID) then -- can we use ID for the "number"?
    ID = Issue; -- yes, use it
    ID = Issue; -- yes, use it
    Line 1,201: Line 1,260:
    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
    -- 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.
    if not is_set(Date) then
    Date = Year; -- promote Year to Date
    Year = nil; -- make nil so Year as empty string isn't used for CITEREF
    if is_set(Date) then
    local Month = A['Month'];
    if is_set(Month) then
    Date = Month .. " " .. Date;
    local Day = A['Day']
    if is_set(Day) then Date = Day .. " " .. Date end
    end
    elseif is_set(PublicationDate) then -- use PublicationDate when |date= and |year= are not set
    Date = PublicationDate; -- promonte PublicationDate to Date
    PublicationDate = ''; -- unset, no longer needed
    end
    end
    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.
    -- Go test all of the date-holding parameters for valid MOS:DATE format and make sure that dates are real dates.
    Line 1,207: Line 1,285:
    ['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});
    ['embargo']=Embargo, ['laydate']=LayDate, ['publicationdate']=PublicationDate, ['year']=Year});


    if not is_set(Year) then -- prevent Year from being set from DateIn  TODO: eliminate the need for this?
    -- At this point fields may be nil if they weren't specified in the template use.  We can use that fact.
    if is_set(anchor_year) then
     
    Year = anchor_year;
    --Account for the oddity that is {{cite journal}} with |pmc= set and |url= not set
    if config.CitationClass == "journal" and not is_set(URL) and is_set(ID_list['PMC']) then
    if not is_embargoed(Embargo) then
    URL=cfg.id_handlers['PMC'].prefix .. ID_list['PMC']; -- set url to be the same as the PMC external link if not embargoed
    end
    end
    end
    end


    -- At this point fields may be nil if they weren't specified in the template use.  We can use that fact.
       
         -- 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 is_set(BookTitle) then
         if is_set(BookTitle) then
    Line 1,260: Line 1,339:
             ['Title'] = Title,
             ['Title'] = Title,
             ['PublicationPlace'] = PublicationPlace,
             ['PublicationPlace'] = PublicationPlace,
             ['Date'] = first_set(COinS_date, Date, Year, PublicationDate),
             ['Date'] = first_set(COinS_date, Date), -- COinS_date has correctly formatted date if Date is valid; any reason to keep Date here?  Should we be including invalid dates in metadata?
             ['Series'] = Series,
             ['Series'] = Series,
             ['Volume'] = Volume,
             ['Volume'] = Volume,
    Line 1,308: Line 1,387:
                 control.lastauthoramp = nil;
                 control.lastauthoramp = nil;
                 control.maximum = #a + 1;
                 control.maximum = #a + 1;
                deprecated_parameter(); -- |coauthor= and |coathors= are deprecated; add this page to deprecated parameter category
             end
             end
              
              
    Line 1,316: Line 1,394:
    if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified
    if not is_set(Authors) and is_set(Coauthors) then -- coauthors aren't displayed if one of authors=, authorn=, or lastn= isn't specified
    table.insert( z.message_tail, { seterror('coauthors_missing_author', {}, true) } ); -- emit error message
    table.insert( z.message_tail, { seterror('coauthors_missing_author', {}, true) } ); -- emit error message
    deprecated_parameter(); -- |coauthor= and |coathors= are deprecated; add this page to deprecated parameter category
    end
    end


    Line 1,359: Line 1,436:
             end         
             end         
         end
         end
       
        if not is_set(Date) then
            Date = Year;
            if is_set(Date) then
                local Month = A['Month'];
                if is_set(Month) then
                deprecated_parameter(); -- |month= (and also |day=) is deprecated; add this page to deprecated parameter category
                    Date = Month .. " " .. Date;
                    local Day = A['Day']
                    if is_set(Day) then Date = Day .. " " .. Date end
                end
            end
        end
       
        if inArray(PublicationDate, {Date, Year}) then PublicationDate = ''; end
        if not is_set(Date) and is_set(PublicationDate) then
            Date = PublicationDate;
            PublicationDate = '';
        end
        -- Captures the value for Date prior to adding parens or other textual transformations
        local DateIn = Date;
          
          
         if  not is_set(URL) and
         if  not is_set(URL) and
    Line 1,599: Line 1,654:
    ]]
    ]]
    if is_set (Language) then
    if is_set (Language) then
    local name = cfg.iso639_1[Language:lower()]; -- get the language name if Language parameter has a valid iso 639-1 code
    local name = cfg.iso639_1[Language:lower()]; -- get the language name if Language parameter has a valid iso 639-1 code
    if nil == name then
    if nil == name then
    Language=" " .. wrap( 'language', Language ); -- no match, use parameter's value
    Language=" " .. wrap( 'language', Language ); -- no match, use parameter's value
    else
    else
    if 0 == this_page.namespace and 'en' ~= Language:lower() then --found a match; is this page main / article space and English not the language?
    if 0 == this_page.namespace and 'en' ~= Language:lower() then --found a match; is this page main / article space and English not the language?
    Language=" " .. wrap( 'language', name .. '[[Category:Articles with ' .. name .. '-language external links]]' ); -- in main space and not English: categorize
    Language=" " .. wrap( 'language', name .. '[[Category:Articles with ' .. name .. '-language external links]]' ); -- in main space and not English: categorize
    else
    else
    Language=" " .. wrap( 'language', name ); --not in mainspace or language is English so don't categorize
    Language=" " .. wrap( 'language', name ); --not in mainspace or language is English so don't categorize
    end
    end
    end
    else
    Language=""; -- language not specified so make sure this is an empty string;
    end
     
    Others = is_set(Others) and (sepc .. " " .. Others) or "";
     
    -- handle type parameter for those CS1 citations that have default values
     
    if inArray(config.CitationClass, {"pressrelease","techreport","thesis", "speech"}) then
    TitleType = set_titletype (config.CitationClass, TitleType);
    if is_set(Degree) and "Thesis" == TitleType then -- special case for cite thesis
    TitleType = Degree .. " thesis";
    end
    end
    else
    Language=""; -- language not specified so make sure this is an empty string;
    end
    end


    Others = is_set(Others) and (sepc .. " " .. Others) or "";
    -- handle type parameter for those CS1 citations that have default values
    if "pressrelease" == config.CitationClass then -- if this citation is cite press release
    if not is_set (TitleType) then
    TitleType = "Press release"; -- if type not specified, display the press release annotation
    else
    if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed
    end
    elseif "techreport" == config.CitationClass then -- if this citation is cite techreport
    if not is_set (TitleType) then
    TitleType = "Technical report"; -- if type not specified, display the techreport annotation
    else
    if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed; |number=, if set, will be displayed
    end
    elseif "thesis" == config.CitationClass then -- if this citation is cite thesis
    if not is_set (TitleType) then
    if is_set(Degree) then -- if type not specified, display one of the thesis annotations
    TitleType = Degree .. " thesis"; -- if a degree (masters, PhD, ...) is specified include it in the display
    else
    TitleType = "Thesis"; -- otherwise display the simple thesis annotation
    end
    else
    if "none" == TitleType then TitleType = ""; end -- if |type=none then type parameter not displayed
    end
    end
    if is_set(TitleType) then -- if type parameter is specified
    if is_set(TitleType) then -- if type parameter is specified
    TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
    TitleType = " (" .. TitleType .. ")"; -- display it in parentheses
    Line 1,903: Line 1,940:


         -- Now enclose the whole thing in a <span/> element
         -- Now enclose the whole thing in a <span/> element
        if not is_set(Year) then
            if is_set(DateIn) then
                Year = selectyear( DateIn );
            elseif is_set(PublicationDate) then
                Year = selectyear( PublicationDate );
            end
        end
       
         local options = {};
         local options = {};