Difference between revisions of "Module:Archive list"

From blackwiki
Jump to navigation Jump to search
blackwiki>Mr. Stradivarius
(tweak comments)
m (17 revisions imported)
 
(8 intermediate revisions by 5 users not shown)
Line 1: Line 1:
 
-- This module implements {{archive list}} in Lua, and adds a few
 
-- This module implements {{archive list}} in Lua, and adds a few
 
-- new features.
 
-- new features.
 +
 +
-- Process a numeric argument to make sure it is a positive
 +
-- integer.
 +
local function processNumArg( num )
 +
    if num then
 +
        num = tonumber( num )
 +
        if type( num ) == 'number' then
 +
            num = math.floor( num )
 +
            if num >= 0 then
 +
                return num
 +
            end
 +
        end
 +
    end
 +
    return nil
 +
end
  
 
-- Checks whether a page exists, going through pcall
 
-- Checks whether a page exists, going through pcall
Line 43: Line 58:
 
-- maximum of 500,000 possible archives before we hit the
 
-- maximum of 500,000 possible archives before we hit the
 
-- expensive function limit.
 
-- expensive function limit.
local function getBiggestArchiveNum( prefix )
+
local function getBiggestArchiveNum( prefix, start, max )
     local check1000 = checkArchives( prefix, 1000, 1 )
+
    -- Return the value for max if it is specified.
     if check1000 == 1 then
+
    max = processNumArg( max )
 +
    if max then
 +
        return max
 +
    end
 +
   
 +
    -- Otherwise, detect the largest archive number.
 +
    start = start or 1
 +
     local check1000 = checkArchives( prefix, 1000, start )
 +
     if check1000 == start then
 
         return 0 -- Return 0 if no archives were found.
 
         return 0 -- Return 0 if no archives were found.
 
     end
 
     end
Line 57: Line 80:
 
end
 
end
  
local function getPrefix( args )
+
-- Get the archive link prefix (the title of the archive pages
    -- Get the root page.
+
-- minus the number).
     local root = args.root or mw.title.getCurrentTitle().prefixedText
+
local function getPrefix( root, prefix, prefixSpace )
      
+
     local ret = root or mw.title.getCurrentTitle().prefixedText
    -- Get the prefix.
+
     ret = ret .. '/'
    local prefix = root .. '/'
+
     if prefix then
     if args.prefix then
+
         ret = ret .. prefix
         prefix = prefix .. args.prefix
+
         if prefixSpace == 'yes' then
         if args.prefixspace == 'yes' then
+
             ret = ret .. ' '
             prefix = prefix .. ' '
 
 
         end
 
         end
 
     else
 
     else
         prefix = prefix .. 'Archive '
+
         ret = ret .. 'Archive '
 
     end
 
     end
     return prefix
+
     return ret
 
end
 
end
  
-- Generate the archive links from the values found in the
+
-- Get the number of archives to put on one line. Set to
-- other functions.
+
-- math.huge if there should be no line breaks.
local function _main( args )
+
local function getLineNum( links, nobr, isLong )
    -- Get the number of archives to put on one line. Set to
+
     local linksToNum = tonumber( links )
    -- math.huge if there should be no line breaks.
 
     local links = tonumber( args.links )
 
 
     local lineNum
 
     local lineNum
     if args.nobr == 'yes' or (args.links and not links) then
+
     if nobr == 'yes' or (links and not linksToNum) then
 
         lineNum = math.huge
 
         lineNum = math.huge
 
     -- If links is a number, process it. Negative values and expressions
 
     -- If links is a number, process it. Negative values and expressions
 
     -- such as links=8/2 produced some interesting values with the old
 
     -- such as links=8/2 produced some interesting values with the old
 
     -- template, but we will ignore those for simplicity.
 
     -- template, but we will ignore those for simplicity.
     elseif type(links) == 'number' and links >= 0 then
+
     elseif type(linksToNum) == 'number' and linksToNum >= 0 then
 
         -- The old template rounded down decimals to the nearest integer.
 
         -- The old template rounded down decimals to the nearest integer.
         lineNum = math.floor( links )
+
         lineNum = math.floor( linksToNum )
 
         if lineNum == 0 then
 
         if lineNum == 0 then
 
             -- In the old template, values of links between 0 and 0.999
 
             -- In the old template, values of links between 0 and 0.999
Line 95: Line 115:
 
         end
 
         end
 
     else
 
     else
        lineNum = 10 -- Default to 10 links.
+
    if isLong==true then
 +
    lineNum = 3 -- Default to 3 links on long
 +
    else
 +
        lineNum = 10 -- Default to 10 on short
 +
        end
 +
    end
 +
    return lineNum
 +
end
 +
 
 +
-- Gets the prefix to put before the archive links.
 +
local function getLinkPrefix( prefix, space, isLong )
 +
    -- Get the link prefix.
 +
    local ret = ''
 +
    if isLong==true then ---- Default of old template for long is 'Archive '
 +
    if type(prefix) == 'string' then
 +
    if prefix == 'none' then -- 'none' overrides to empty prefix
 +
    ret = ''
 +
    else
 +
    ret = prefix
 +
    if space == 'yes' then
 +
    ret = ret .. ' '
 +
    end
 +
end
 +
else
 +
ret = 'Archive '
 +
end
 +
else --type is not long
 +
if type(prefix) == 'string' then
 +
        ret = prefix
 +
        if space == 'yes' then
 +
            ret = ret .. ' '
 +
        end
 +
    end
 +
    end
 +
    return ret
 +
end
 +
 
 +
-- Get the number to start listing archives from.
 +
local function getStart( start )
 +
    start = processNumArg( start )
 +
    if start then
 +
        return start
 +
    else
 +
        return 1
 +
    end
 +
end
 +
 
 +
-- Process the separator parameter.
 +
local function getSeparator( sep )
 +
    if sep and type(sep) == 'string' then
 +
        if sep == 'dot'
 +
            or sep =='pipe'
 +
            or sep == 'comma'
 +
            or sep == 'tpt-languages' then
 +
            return mw.message.new( sep .. '-separator' ):plain()
 +
        else
 +
            return sep
 +
        end
 +
    else
 +
        return nil
 +
    end
 +
end
 +
 
 +
-- Generates the list of archive links. glargs.max must be either zero (for
 +
-- no archives) or a positive integer value.
 +
local function generateLinks( glargs )
 +
    if type( glargs ) ~= 'table' or not glargs.max or not glargs.prefix then
 +
        error('insufficient arguments passed to generateLinks', 2)
 
     end
 
     end
   
 
    -- Get the prefix and the biggest archive number.
 
    local prefix = getPrefix ( args )
 
    local archiveMax = getBiggestArchiveNum( prefix )
 
   
 
 
     -- If there are no archives yet, return a message and a
 
     -- If there are no archives yet, return a message and a
 
     -- link to create Archive one.
 
     -- link to create Archive one.
     if archiveMax == 0 then
+
     if glargs.max == 0 then
        return 'no archives yet ([[' .. prefix .. '1|create]])'
+
    if glargs.isLong == true then
 +
    glargs.max = 1 -- One archive redlink is displayed for Long format
 +
    else -- Short error and a creat link is displayed for short
 +
        return 'no archives yet ([[' .. glargs.prefix .. '1|create]])'
 +
        end
 +
    end
 +
    -- Return an html error if the start number is greater than the
 +
    -- maximum number.
 +
    local start = glargs.start or 1
 +
    if start > glargs.max then
 +
        return '<span class="error">Start value "'
 +
            .. tostring( start )
 +
            .. '" is greater than the most recent archive number "'
 +
            .. tostring( glargs.max )
 +
            .. '".</span>'
 
     end
 
     end
      
+
     local linkPrefix = glargs.linkPrefix or ''
     -- Get the link prefix.
+
        local lineNum = glargs.lineNum or 10
     local linkprefix = ''
+
     local sep = '' -- Long default separator is cell elements, short is ', '
     if args.linkprefix then
+
     local lineSep = '' -- Long default linebreak is row elements short is '\n'
        linkprefix = args.linkprefix
+
     if glargs.isLong==true then  
        if args.linkprefixspace == 'yes' then
+
    sep = glargs.sep or ''
            linkprefix = linkprefix .. ' '
+
    sep = sep .. '</td><td>'
        end
+
    lineSep = glargs.lineSep or ''
 +
lineSep = lineSep .. '</td></tr><tr><td>'
 +
    else
 +
    sep = glargs.sep or mw.message.new( 'comma-separator' ):plain()
 +
    lineSep = glargs.lineSep or '<br />'
 
     end
 
     end
   
 
 
     -- Generate the archive links.
 
     -- Generate the archive links.
 
     local lineCounter = 1 -- The counter to see whether we need a line break or not.
 
     local lineCounter = 1 -- The counter to see whether we need a line break or not.
     local ret = '' -- The string to return.
+
     local ret = {} -- A table containing the strings to be returned.
     for archiveNum = 1, archiveMax do
+
    if glargs.isLong == true then --Long version is a table
         ret = ret .. '[[' .. prefix .. tostring(archiveNum) .. '|' .. linkprefix .. tostring(archiveNum) .. ']]'
+
    table.insert(ret, "<table style=\"width: 100%; padding: 0px; text-align: center; background-color: transparent;\"><tr><td>")
 +
    end
 +
     for archiveNum = start, glargs.max do
 +
         local link = mw.ustring.format(
 +
            '[[%s%d|%s%d]]',
 +
            glargs.prefix, archiveNum, linkPrefix, archiveNum
 +
        )
 +
        table.insert( ret, link )
 
         -- If we don't need a new line, output a comma. We don't need
 
         -- If we don't need a new line, output a comma. We don't need
 
         -- a comma after the last link.  
 
         -- a comma after the last link.  
         if lineCounter < lineNum and archiveNum < archiveMax then
+
         if lineCounter < lineNum and archiveNum < glargs.max then
             ret = ret .. ', '
+
             table.insert( ret, sep )
 
             lineCounter = lineCounter + 1
 
             lineCounter = lineCounter + 1
 
         -- Output new lines if needed. We don't need a new line after
 
         -- Output new lines if needed. We don't need a new line after
 
         -- the last link.
 
         -- the last link.
         elseif lineCounter >= lineNum and archiveNum < archiveMax then
+
         elseif lineCounter >= lineNum and archiveNum < glargs.max then
             ret = ret .. '<br />'
+
             table.insert( ret, lineSep )
 
             lineCounter = 1
 
             lineCounter = 1
 
         end
 
         end
 
     end
 
     end
     return ret
+
    if glargs.isLong == true then --Long version is a table
 +
    table.insert(ret, "</td></tr></table>")
 +
    end
 +
     return table.concat( ret )
 +
end
 +
 
 +
-- Determine if format should be long
 +
local function findFormType( auto )
 +
if auto == nil or auto == '' then
 +
return false
 +
elseif auto == 'long' then
 +
return true
 +
else
 +
return false
 +
end
 +
end
 +
 
 +
-- Get the archive data and pass it to generateLinks().
 +
local function _main( args )
 +
local isLong = findFormType( args.auto )
 +
    local prefix = getPrefix( args.root, args.prefix, args.prefixspace )
 +
    local lineNum = getLineNum( args.links, args.nobr, isLong )
 +
    local linkPrefix = getLinkPrefix( args.linkprefix, args.linkprefixspace, isLong )
 +
    local start = getStart( args.start )
 +
    local max = getBiggestArchiveNum( prefix, start, args.max )
 +
    local sep = getSeparator( args.sep )
 +
    local lineSep = getSeparator( args.linesep )
 +
    local glargs = {
 +
        start = start,
 +
        max = max,
 +
        prefix = prefix,
 +
        linkPrefix = linkPrefix,
 +
        isLong = isLong,
 +
        sep = sep,
 +
        lineNum = lineNum,
 +
        lineSep = lineSep
 +
    }
 +
    return generateLinks( glargs )
 
end
 
end
  
Line 140: Line 283:
 
-- #invoke.
 
-- #invoke.
 
local function _count( args )
 
local function _count( args )
     local prefix = getPrefix( args )
+
     local prefix = getPrefix( args.root, args.prefix, args.prefixspace )
 
     local archiveMax = getBiggestArchiveNum( prefix )
 
     local archiveMax = getBiggestArchiveNum( prefix )
 
     return archiveMax
 
     return archiveMax
Line 162: Line 305:
 
         end
 
         end
 
          
 
          
         -- Trim whitespace from all arguments, and ignore blank values for
+
         -- Ignore blank values for parameters other than "links",
        -- parameters other than "links", which functions differently
+
         -- which functions differently depending on whether it is
         -- depending on whether it is blank or absent.
+
        -- blank or absent.
 
         local args = {}
 
         local args = {}
 
         for k, v in pairs( origArgs ) do
 
         for k, v in pairs( origArgs ) do
            v = mw.text.trim(v)
 
 
             if k == 'links' or v ~= '' then
 
             if k == 'links' or v ~= '' then
 
                 args[k] = v
 
                 args[k] = v

Latest revision as of 13:09, 26 September 2020

Module:Archive list can be applied to any talk page or discussion archive, and will return links to all the numbered archives of that page or its parent page. By default the module uses the naming convention specified at WP:ARCHIVE, Talk:PAGENAME/Archive 1, with a capital A, a space before the number, and no leading zeros. This module should not usually be substituted – that way, the list of links will update itself whenever a new numbered archive is added. For ease of access, {{archive list}} can be used.

This module can be used with {{Archives}} to produce a box of numbered archive links without entering them all manually. To do this, use {{archive box|auto=yes}}.

Usage

Main

The main function. Returns a list of archive links.

{{#invoke:Archive list|main
| root            = 
| links           = 
| nobr            = 
| prefix          = 
| prefixspace     = 
| linkprefix      = 
| linkprefixspace = 
| sep             = 
| linesep         = 
| start           = 
| max             = 
| auto            =
}}
Count

The count function. Returns the number of the most recent archive.

{{#invoke:Archive list|count
| root            = 
| prefix          = 
| prefixspace     = 
}}

Parameters

Valid parameters are:

  • root = <root> - use this to specify a root other than that of the page from which the template is transcluded.
  • links = # - the number of links to display per line. The default is 10.
  • nobr = yes - set this to yes to remove all line breaks. This parameter cannot be used in conjunction with |links=.
  • prefix = <prefix> - a custom prefix for the archives, without the number. The default is "Archive ".
  • prefixspace = yes - adds a space between the prefix and the archive number for prefixes specified with |prefix=.
  • linkprefix = <linkprefix> - a custom prefix for the display links, without the number. The default is blank. If auto=long, use 'none' to have it blank.
  • prefixspace = yes - adds a space between the link prefix and the archive number for prefixes specified with |linkprefix=.
  • sep = <sep> - the separator for archive links. The default value is the comma separator for the language set in your preferences: ", ". If this is set to either dot (⧼dot-separator⧽), pipe ( | ), comma (, ), or tpt-languages ( • ), then it uses that separator as specified for your default language. If it is any other value, that value is used as it is. If this module is called from #invoke then whitespace is stripped, but if called from another module then whitespace is preserved. This allows for other modules to use this module to create wikitables, etc. If called from #invoke, the whitespace problem can be worked around by using &#32; (for spaces) and <br /> (for new lines).
  • linesep = <linesep> - the separator for lines of archive links. The possible input values are the same as for the |sep= parameter, and the default separator text is <br />. How often the value is displayed depends on the value of |links=.
  • start = # - the archive number to start listing archives from. This must be smaller than the largest archive number, or |max= if it is specified.
  • max = # - the largest archive number to list. This overrides the automatic detection of archive page numbers.
  • auto = long - outputs as a table. Changes default value of links to 3 and linkprefix to 'Archive '.

Limitations

The old {{archive list}} template was limited to detecting 200 archives. This module has no such limitation. However, at very high numbers of archives this module might reach the expensive function call limit. On a page with no other templates that call expensive functions, this module should be able to output 400,000+ archive links. On pages with other templates that make expensive function calls, the module may fail sooner.


-- This module implements {{archive list}} in Lua, and adds a few
-- new features.

-- Process a numeric argument to make sure it is a positive
-- integer.
local function processNumArg( num )
    if num then
        num = tonumber( num )
        if type( num ) == 'number' then
            num = math.floor( num )
            if num >= 0 then
                return num
            end
        end
    end
    return nil
end

-- Checks whether a page exists, going through pcall
-- in case we are over the expensive function limit.
local function checkPageExists( title )
    if not title then
        error('No title passed to checkArchiveExists', 2)
    end
    local noError, titleObject = pcall(mw.title.new, title)
    if not noError then
        -- If we are over the expensive function limit then assume
        -- that the page doesn't exist.
        return false
    else
        if titleObject then
            return titleObject.exists
        else
            return false -- Return false if given a bad title.
        end
    end
end

-- Checks every nth archive to see if it exists, and returns the
-- number of the first archive that doesn't exist. It is
-- necessary to do this in batches because each check is an
-- expensive function call, and we want to avoid making too many
-- of them so as not to go over the expensive function limit.
local function checkArchives( prefix, n, start )
    local i = start
    local exists = true
    while exists do
        exists = checkPageExists( prefix .. tostring( i ) )
        if exists then
            i = i + n
        end
    end
    return i
end

-- Return the biggest archive number, using checkArchives()
-- and starting in intervals of 1000. This should get us a
-- maximum of 500,000 possible archives before we hit the
-- expensive function limit.
local function getBiggestArchiveNum( prefix, start, max )
    -- Return the value for max if it is specified.
    max = processNumArg( max )
    if max then
        return max
    end
    
    -- Otherwise, detect the largest archive number.
    start = start or 1
    local check1000 = checkArchives( prefix, 1000, start )
    if check1000 == start then
        return 0 -- Return 0 if no archives were found.
    end
    local check200 = checkArchives( prefix, 200, check1000 - 1000 )
    local check50 = checkArchives( prefix, 50, check200 - 200 )
    local check10 = checkArchives( prefix, 10, check50 - 50 )
    local check1 = checkArchives( prefix, 1, check10 - 10 )
    -- check1 is the first page that doesn't exist, so we want to
    -- subtract it by one to find the biggest existing archive.
    return check1 - 1
end

-- Get the archive link prefix (the title of the archive pages
-- minus the number).
local function getPrefix( root, prefix, prefixSpace )
    local ret = root or mw.title.getCurrentTitle().prefixedText
    ret = ret .. '/'
    if prefix then
        ret = ret .. prefix
        if prefixSpace == 'yes' then
            ret = ret .. ' '
        end
    else
        ret = ret .. 'Archive '
    end
    return ret
end

-- Get the number of archives to put on one line. Set to
-- math.huge if there should be no line breaks.
local function getLineNum( links, nobr, isLong )
    local linksToNum = tonumber( links )
    local lineNum
    if nobr == 'yes' or (links and not linksToNum) then
        lineNum = math.huge
    -- If links is a number, process it. Negative values and expressions
    -- such as links=8/2 produced some interesting values with the old
    -- template, but we will ignore those for simplicity.
    elseif type(linksToNum) == 'number' and linksToNum >= 0 then
        -- The old template rounded down decimals to the nearest integer.
        lineNum = math.floor( linksToNum )
        if lineNum == 0 then
            -- In the old template, values of links between 0 and 0.999
            -- suppressed line breaks.
            lineNum = math.huge
        end
    else
    	if isLong==true then
    		lineNum = 3 -- Default to 3 links on long
    	else
        	lineNum = 10 -- Default to 10 on short
        end
    end
    return lineNum
end

-- Gets the prefix to put before the archive links.
local function getLinkPrefix( prefix, space, isLong )
    -- Get the link prefix.
    local ret = ''
    if isLong==true then ---- Default of old template for long is 'Archive '
    	if type(prefix) == 'string' then
    		if prefix == 'none' then -- 'none' overrides to empty prefix
    			ret = ''
    		 else
    		 	ret = prefix
    		 	if space == 'yes' then
    		 		ret = ret .. ' '
    		 	end
		 	end
	 	else
	 		ret = 'Archive '
		end
	else --type is not long
		if type(prefix) == 'string' then
        	ret = prefix
        	if space == 'yes' then
        	    ret = ret .. ' '
        	end
    	end
    end
    return ret
end

-- Get the number to start listing archives from.
local function getStart( start )
    start = processNumArg( start )
    if start then
        return start
    else
        return 1
    end
end

-- Process the separator parameter.
local function getSeparator( sep )
    if sep and type(sep) == 'string' then
        if sep == 'dot' 
            or sep =='pipe'
            or sep == 'comma'
            or sep == 'tpt-languages' then
            return mw.message.new( sep .. '-separator' ):plain()
        else
            return sep
        end
    else
        return nil
    end
end

-- Generates the list of archive links. glargs.max must be either zero (for
-- no archives) or a positive integer value.
local function generateLinks( glargs )
    if type( glargs ) ~= 'table' or not glargs.max or not glargs.prefix then
        error('insufficient arguments passed to generateLinks', 2)
    end
    -- If there are no archives yet, return a message and a
    -- link to create Archive one.
    if glargs.max == 0 then
    	if glargs.isLong == true then
    		glargs.max = 1 -- One archive redlink is displayed for Long format
    	else -- Short error and a creat link is displayed for short
        	return 'no archives yet ([[' .. glargs.prefix .. '1|create]])'
        end
    end
    -- Return an html error if the start number is greater than the 
    -- maximum number.
    local start = glargs.start or 1
    if start > glargs.max then
        return '<span class="error">Start value "' 
            .. tostring( start ) 
            .. '" is greater than the most recent archive number "' 
            .. tostring( glargs.max ) 
            .. '".</span>'
    end
    local linkPrefix = glargs.linkPrefix or ''
        local lineNum = glargs.lineNum or 10
    local sep = '' -- Long default separator is cell elements, short is ', '
    local lineSep = '' -- Long default linebreak is row elements short is '\n'
    if glargs.isLong==true then 
    	sep = glargs.sep or ''
    	sep = sep .. '</td><td>'
    	lineSep = glargs.lineSep or ''
		lineSep = lineSep .. '</td></tr><tr><td>'
    else
    	sep = glargs.sep or mw.message.new( 'comma-separator' ):plain()
    	lineSep = glargs.lineSep or '<br />'
    end
    -- Generate the archive links.
    local lineCounter = 1 -- The counter to see whether we need a line break or not.
    local ret = {} -- A table containing the strings to be returned.
    if glargs.isLong == true then --Long version is a table
    	table.insert(ret, "<table style=\"width: 100%; padding: 0px; text-align: center; background-color: transparent;\"><tr><td>")
    end
    for archiveNum = start, glargs.max do
        local link = mw.ustring.format(
            '[[%s%d|%s%d]]',
            glargs.prefix, archiveNum, linkPrefix, archiveNum
        )
        table.insert( ret, link )
        -- If we don't need a new line, output a comma. We don't need
        -- a comma after the last link. 
        if lineCounter < lineNum and archiveNum < glargs.max then
            table.insert( ret, sep )
            lineCounter = lineCounter + 1
        -- Output new lines if needed. We don't need a new line after
        -- the last link.
        elseif lineCounter >= lineNum and archiveNum < glargs.max then
            table.insert( ret, lineSep )
            lineCounter = 1
        end
    end
    if glargs.isLong == true then --Long version is a table
    	table.insert(ret, "</td></tr></table>")
    end
    return table.concat( ret )
end

-- Determine if format should be long
local function findFormType( auto )
	if auto == nil or auto == '' then
		return false
	elseif auto == 'long' then
			return true
	else
		return false
	end
end

-- Get the archive data and pass it to generateLinks().
local function _main( args )
	local isLong = findFormType( args.auto )
    local prefix = getPrefix( args.root, args.prefix, args.prefixspace )
    local lineNum = getLineNum( args.links, args.nobr, isLong )
    local linkPrefix = getLinkPrefix( args.linkprefix, args.linkprefixspace, isLong )
    local start = getStart( args.start )
    local max = getBiggestArchiveNum( prefix, start, args.max )
    local sep = getSeparator( args.sep )
    local lineSep = getSeparator( args.linesep )
    local glargs = {
        start = start,
        max = max,
        prefix = prefix,
        linkPrefix = linkPrefix,
        isLong = isLong,
        sep = sep,
        lineNum = lineNum,
        lineSep = lineSep
    }
    return generateLinks( glargs )
end

-- A wrapper function to make getBiggestArchiveNum() available from
-- #invoke.
local function _count( args )
    local prefix = getPrefix( args.root, args.prefix, args.prefixspace )
    local archiveMax = getBiggestArchiveNum( prefix )
    return archiveMax
end

function makeWrapper( func )
    return function( frame )
        -- If we are being called from #invoke, get the args from #invoke
        -- if they exist, or else get the arguments passed to the parent
        -- frame. Otherwise, assume the arguments are being passed directly
        -- in from another module or from the debug console.
        local origArgs
        if frame == mw.getCurrentFrame() then
            origArgs = frame:getParent().args
            for k, v in pairs( frame.args ) do
                origArgs = frame.args
                break
            end
        else
            origArgs = frame
        end
        
        -- Ignore blank values for parameters other than "links",
        -- which functions differently depending on whether it is
        -- blank or absent.
        local args = {}
        for k, v in pairs( origArgs ) do
            if k == 'links' or v ~= '' then
                args[k] = v
            end
        end
        
        return func( args )
    end
end

return {
    main = makeWrapper( _main ),
    count = makeWrapper( _count )
}