Module:Portal: Difference between revisions

Content deleted Content added
add two entry points to simplify Module:Portal bar, clean up tracking logic. No behavior changes.
update per Talk: centralize portal checking into p._checkPortals(), use Module:Arguments to trim whitespace, correctly handle default arguments
Line 41:
 
local p = {}
 
local trackingEnabled = true
 
local templatestyles = 'Module:Portal/styles.css'
 
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
 
Line 77 ⟶ 76:
end
 
--Entry point to checkCheck if page should be category tracked
--Arguments:
-- title (optional): mw.title.Title object to evaluate. Defaults to current page
--Returns:
-- bool whether page should be tracked
local function p._checkTrackingcheckTracking(title)
title = title or mw.title.getCurrentTitle()
return checkTrackingNamespace(title) and checkTrackingPagename(title)
Line 123 ⟶ 122:
end
 
-- Function to check argument portals for errors, generate tracking categories if needed
local function checkPortalExists(portal)
-- Function first checks for too few/many portals provided
return not (mw.title.makeTitle(100, portal).id == 0)
-- Then checks the portal list to purge any portals that don't exist
-- Arguments:
-- portals: raw list of portals
-- args.tracking: is tracking requested? (will not track on bad titles or namespaces)
-- args.redlinks: should redlinks be displayed?
-- args.minPortals: minimum number of portal arguments
-- args.maxPortals: maximum number of portal arguments
-- Returns:
-- portals = list of portals, with redlinks purged (if args.redlinks=false)
-- trackingCat = possible tracking category
-- errorMsg = error message
function p._checkPortals(portals, args)
local trackingCat = ''
local errMsg = nil
-- Tracking is on by default.
-- It is disabled if any of the following is true
-- 1/ the parameter "tracking" is set to 'no, 'n', or 'false'
-- 2/ the current page fails the namespace or pagename tests
local trackingEnabled = args.tracking and checkTracking()
args.minPortals = args.minPortals or 1
args.maxPortals = args.maxPortals or -1
-- check for too few portals
if #portals < args.minPortals then
errMsg = 'please specify at least '..args.minPortals..' portal'..(args.minPortals > 1 and 's' or '')
trackingCat = (trackingEnabled and '[[Category:Portal templates with too few portals]]' or '')
return portals, trackingCat, errMsg
end
-- check for too many portals
if args.maxPortals >= 0 and #portals > args.maxPortals then
errMsg = 'too many portals (maximum = '..args.maxPortals..')'
trackingCat = (trackingEnabled and '[[Category:Portal templates with too many portals]]' or '')
return portals, trackingCat, errMsg
end
if not args.redlinks or trackingEnabled then
-- make new list of portals that exist
local existingPortals = {}
for _, portal in ipairs(portals) do
local portalTitle = mw.title.new(portal,"Portal")
-- if portal exists, put it into list
if portalTitle and portalTitle.exists then
table.insert(existingPortals,portal)
-- otherwise set tracking cat
elseif trackingEnabled then
trackingCat = "[[Category:Portal templates with redlinked portals]]"
end
end
-- If redlinks is off, use portal list purged of redlinks
portals = args.redlinks and portals or existingPortals
-- if nothing left after purge, set tracking cat
if #portals == 0 then
trackingCat = trackingEnabled and "[[Category:Portal templates with all redlinked portals]]" or ""
end
end
return portals, trackingCat, errMsg
end
 
function p._portal(portals, args)
-- This function builds the portal box used by the {{portal}} template.
-- Normalize all arguments
if args.redlinks == 'include' then args.redlinks = true end
args.addBreak = args['break']
for key, default in pairs({left=false,tracking=true,nominimum=false,redlinks=false,addBreak=false}) do
if args[key] == nil then args[key] = default end
args[key] = yesno(args[key], default)
end
 
local root = mw.html.create('div')
:attr('role', 'navigation')
Line 137 ⟶ 201:
:newline()
 
local trackingCat = ''
-- Tracking is on by default.
local errMsg = nil
-- It is disabled if any of the following is true
args.minPortals = args.nominimum and 0 or 1
-- 1/ the parameter "tracking" is set to 'no, 'n', or 'false'
args.maxPortals = -1
-- 2/ the current page fails the namespace tests in checkTrackingNamespace()
portals, trackingCat, errMsg = p._checkPortals(portals, args)
-- 3/ the current page fails the pagename tests in checkTrackingPagename()
root:wikitext(trackingCat)
trackingEnabled = yesno(args.tracking, trackingEnabled)
-- if error message, put it in the box and return
if (checkTrackingNamespace() == false) then
if errMsg then
trackingEnabled = false
local errTag = root:tag('strong')
end
errTag:addClass('error')
if (checkTrackingPagename() == false) then
errTag:css('padding','0.2em')
trackingEnabled = false
errTag:wikitext('Error: '..errMsg)
end
 
-- If no portals have been specified, display an error and add the page to a tracking category.
if not portals[1] then
if yesno(args.nominimum) then
-- if nominimum as been set to yes (or similar), omit the warning
else
root:wikitext('<strong class="error">No portals specified: please specify at least one portal</strong>')
end
if (trackingEnabled) then
root:wikitext('[[Category:Portal templates without a parameter]]')
end
return tostring(root)
end
-- if no portals (and no error), just return tracking category
if #portals == 0 then
-- scan for nonexistent portals, if they exist remove them from the portals table. If redlinks=yes, then don't remove
return trackingCat
local portallen = #portals
-- traverse the list backwards to ensure that no portals are missed (table.remove also moves down the portals in the list, so that the next portal isn't checked if going fowards.
-- going backwards allows us to circumvent this issue
for i=portallen,1,-1 do
-- the use of pcall here catches any errors that may occour when attempting to locate pages when the page name is invalid
-- if pcall returns true, then rerun the function to find if the page exists
if not pcall(checkPortalExists, portals[i]) or not checkPortalExists(portals[i]) then
-- Getting here means a redlinked portal has been found
if yesno(args.redlinks) or (args.redlinks == 'include') then
-- if redlinks as been set to yes (or similar), add the cleanup category and then break the loop before the portal is removed from the list
if (trackingEnabled) then
root:wikitext('[[Category:Portal templates with redlinked portals]]')
end
break
end
-- remove the portal (this does not happen if redlinks=yes)
table.remove(portals,i)
end
end
-- if the length of the table is different, then rows were removed from the table, so portals were removed. If this is the case add the cleanup category
if not (portallen == #portals) then
if (trackingEnabled) then
if #portals == 0 then
return '[[Category:Portal templates with all redlinked portals]]'
else
root:wikitext('[[Category:Portal templates with redlinked portals]]')
end
end
end
 
-- Start the list. This corresponds to the start of the wikitext table in the old [[Template:Portal]].
local listroot = root:tag('ul')
:css('width', type(tonumber(args.boxsize) ==or 'string'0) > 0 and (args.boxsize .. 'px') or nilargs.boxsize)
 
-- Display the portals specified in the positional arguments.
Line 212 ⟶ 236:
:done()
:tag('span')
:wikitext(string.format('[[Portal:%s|%s%sportal]]', portal, portal, args['break'].addBreak and '<br />' or ' '))
end
return tostring(root)
Line 301 ⟶ 325:
-- template, or the args passed to #invoke if any exist. Otherwise
-- assume args are being passed directly in from the debug console
-- or from another Lua module.
-- Also: trim whitespace and remove blank arguments
local origArgs
local origArgs = getArgs(frame)
if type(frame.getParent) == 'function' then
-- create two tables to pass to func: an array of portal names, and a table of named arguments.
origArgs = frame:getParent().args
local portals, args = processPortalArgs(origArgs)
for k, v in pairs(frame.args) do
origArgs = frame.args
break
end
else
origArgs = frame
end
-- Trim whitespace and remove blank arguments.
local args = {}
for k, v in pairs(origArgs) do
if type(v) == 'string' then
v = mw.text.trim(v)
end
if v ~= '' then
args[k] = v
end
end
local results = ''
if funcName == '_portal' or funcName == '_displayAll' then
results = frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles} }
end
return results .. p[funcName](processPortalArgs(portals, args)) -- passes two tables to func: an array of portal names, and a table of named arguments.
end
end