Module:Archive list/sandbox explained

-- 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 nilend

-- 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 endend

-- 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 iend

-- 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 - 1end

-- 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 retend

-- 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 lineNumend

-- 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 retend

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

-- Get whether to leave a blank cell in the first row and column -- If links start at 1, and lineNum is a round number, this aligns the first -- column to start on a multiple of lineNum, which may be a nice round number local function getLeaveFirstCellBlank(leaveFirstCellBlank) return leaveFirstCellBlank

'yes' or leaveFirstCellBlank

'y' or leaveFirstCellBlank

1 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 endend

-- 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 (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 '

Start value "' .. tostring(start) .. '" is greater than the most recent archive number "' .. tostring(glargs.max) .. '".' 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 .. '' lineSep = glargs.lineSep or lineSep = lineSep .. '' else sep = glargs.sep or mw.message.new('comma-separator'):plain lineSep = glargs.lineSep or '
' 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, "

") end if glargs.leaveFirstCellBlank then -- An empty first cell aligns the first column on multiples of lineNum table.insert(ret, sep) lineCounter = lineCounter + 1 end for archiveNum = start, glargs.max do local link = mw.ustring.format('%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, "

") end return table.concat(ret)end

-- Determine if format should be longlocal function findFormType(auto) if auto

nil or auto

then return false elseif auto

'long' then return true else return false endend

-- 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 leaveFirstCellBlank = getLeaveFirstCellBlank(args.leavefirstcellblank) local glargs = 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 archiveMaxend

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) endend

return