Module:Portal bar
Documentation for this module may be created at Module:Portal bar/doc
-- This module implements {{portal bar}}. require('Module:No globals') local getImageName = require( 'Module:Portal' ).image local yesno = require( 'Module:Yesno' ) local p = {} local function checkPortalExists(portal) return not (mw.title.makeTitle(100, portal).id == 0) end -- Check whether to do tracking in this namespace -- Returns true unless the page is one of the banned namespaces local function isTrackedNamespace() local thisPageNS = mw.title.getCurrentTitle().namespace return thisPageNS ~= 1 -- Talk and thisPageNS ~= 2 -- User and thisPageNS ~= 3 -- User talk and thisPageNS ~= 5 -- Wikipedia talk and thisPageNS ~= 7 -- File talk and thisPageNS ~= 11 -- Template talk and thisPageNS ~= 15 -- Category talk and thisPageNS ~= 101 -- Portal talk and thisPageNS ~= 118 -- Draft and thisPageNS ~= 119 -- Draft talk and thisPageNS ~= 829 -- Module talk end -- Check whether to do tracking on this pagename -- Returns false if the page title matches one of the banned strings -- Otherwise returns true local function isTrackedPagename() local thisPageLC = mw.ustring.lower(mw.title.getCurrentTitle().text) local match = string.match return match(thisPageLC, "/archive") == nil and match(thisPageLC, "/doc") == nil and match(thisPageLC, "/test") == nil end -- Builds the portal bar used by {{portal bar}}. function p._main( portals, args ) -- Don't display a blank navbox if no portals were specified. if #portals < 1 then return '' end local nav = mw.html.create( 'ul' ) :addClass( 'portal-bar noprint metadata' ) :attr( 'role', 'navigation' ) :attr( 'aria-label' , 'Portals' ) if yesno( args.border ) == false then nav :addClass('portal-bar-unbordered') else nav :addClass( 'portal-bar-bordered' ) end local trackingEnabled = true local tracking = args.tracking if (tracking == 'no' or tracking == 'n' or tracking == 'false') or not isTrackedNamespace() or not isTrackedPagename() then trackingEnabled = false end -- TODO: This used to say 'if no portals are specified', but we return early -- above. Someone should check whether this is really 'portals[1]' or #portals < 0. -- I don't believe the block in the conditional is reachable currently -- because if it were we would probably get a Lua script error because -- warning was previously undefined -- If the first portal is not specified, -- display an error and add the page to a tracking category. if not portals[1] then local nominimum = args.nominimum local warning = mw.html.create() if nominimum ~= 'yes' and nominimum ~= 'y' and nominimum ~= 'true' then warning:tag('strong') :addClass('error') :wikitext('No portals specified: please specify at least one portal') end if trackingEnabled then warning:wikitext('[[Category:Portal templates without a parameter]]') end return tostring(warning) end -- scan for nonexistent portals, if they exist remove them from the portals -- table. If redlinks=yes, then don't remove 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 local redlinks = args.redlinks if redlinks == 'yes' or redlinks == 'y' or redlinks == 'true' or 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 nav:wikitext('[[Category:Portal templates with redlinked portals]]') end -- TODO: This looks buggy given the comment above; we will always -- break if redlinks are yes, whether or not tracking is enabled 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 portallen ~= #portals then if #portals == 0 then if trackingEnabled then return '[[Category:Portal templates with all redlinked portals]]' else return "" end end if trackingEnabled then nav:wikitext('[[Category:Portal templates with redlinked portals]]') end end for _, portal in ipairs( portals ) do nav :tag( 'li' ) :tag( 'span' ) :wikitext( string.format( '[[File:%s|24x21px|alt=]]', getImageName{ portal } ) ) :done() :wikitext( string.format( '[[Portal:%s|%s portal]]', portal, portal ) ) end return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Module:Portal bar/styles.css' } } .. tostring( nav ) end -- Processes external arguments and sends them to the other functions. function p.main( frame ) -- If called via #invoke, use the args passed into the invoking 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. local origArgs if type( frame.getParent ) == 'function' then origArgs = frame:getParent().args for k, v in pairs( frame.args ) do origArgs = frame.args break end else origArgs = frame end -- Process the args to make an array of portal names that can be used with -- ipairs. We need to use ipairs because we want to list all the portals in -- the order they were passed to the template, but we also want to be able -- to deal with positional arguments passed explicitly, for example -- {{portal|2=Politics}}. The behaviour of ipairs is undefined if nil values -- are present, so we need to make sure they are all removed. local portals, args = {}, {} for k, v in pairs( origArgs ) do -- Make sure we have no non-string portal names. if type( k ) == 'number' and type( v ) == 'string' then if mw.ustring.find( v, '%S' ) then -- Remove blank values. table.insert( portals, k ) end elseif type( k ) ~= 'number' then -- Separate named arguments from portals. if type( v ) == 'string' then v = mw.text.trim( v ) end args[ k ] = v end end table.sort( portals ) for i, v in ipairs( portals ) do -- Swap keys with values, trimming whitespace. portals[ i ] = mw.text.trim( origArgs[ v ] ) end return p._main( portals, args ) end return p