Module:Portal
From Soyjak Wiki, the free ensoyclopedia
Jump to navigationJump to search
| This module is rated as ready for general use. It is considered stable and may be used wherever appropriate. Improvements should be developed and tested in a sandbox before changing the live module. |
| This module depends on the following other modules: |
This module uses TemplateStyles. Click here to edit.
This module implements {{Portal}} and provides other functionalities. See the template documentation for more usage info.
Portal images and aliases are defined in Module:Portal/images.
Portal image data
Portal images[a] and aliases[b]. /images uses the following format:
return {
images = {
['portal name'] = 'icon.png|link=',
['another portal name'] = 'another icon.png|link=',
},
aliases = {
['alternate name'] = 'portal name',
['another alternate name'] = 'another portal name'
},
}
Image keys must be lowercase portal names. Image values contain the filename without the File: prefix and may include additional file arguments after the filename. The only recommended argument is link=.
Alias keys must be lowercase. Each alias value must correspond directly to a key in the images table. Aliases must not point to other aliases.
Aliases affect image lookup only. They do not change the generated portal link or redirect one portal name to another.
Notes
--[[
Fork of https://en.wikipedia.org/wiki/Module:Portal
Forked by User:Rickert
]]
local p = {}
local templatestyles = 'Module:Portal/styles.css'
local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local imageData = mw.loadData('Module:Portal/images')
local badNamespaces = {4, 10}
local function checkTracking(title)
local thisPage = title or mw.title.getCurrentTitle()
if thisPage.isTalkPage then
return false
end
local ns = thisPage.namespace
for _, v in ipairs(badNamespaces) do
if ns == v then
return false
end
end
return true
end
local function matchImagePage(s)
if type(s) ~= 'string' or #s < 1 then return end
return imageData.images[s]
end
local function getAlias(s)
return imageData.aliases[s]
end
local defaultImage = 'Portal-puzzle.svg|link='
local function getImageName(s)
if type(s) ~= 'string' or #s < 1 then
return defaultImage
end
s = mw.ustring.lower(s)
local image = matchImagePage(s) or matchImagePage(getAlias(s)) or defaultImage
image = mw.ustring.gsub(image,'^File:','')
image = mw.ustring.gsub(image,'^Image:','')
return image
end
local function exists(title)
local success, exists = pcall(function() return title.exists end)
return not success or exists
end
function p._checkPortals(portals, args)
local trackingCat = ''
local errMsg = nil
local trackingEnabled = args.tracking and checkTracking()
args.minPortals = args.minPortals or 1
args.maxPortals = args.maxPortals or -1
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
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
local existingPortals = {}
for _, portal in ipairs(portals) do
local portalTitle = mw.title.new(portal,"Portal")
if portalTitle and exists(portalTitle) then
table.insert(existingPortals,portal)
elseif trackingEnabled then
trackingCat = "[[Category:Portal templates with redlinked portals]]"
end
end
portals = args.redlinks and portals or existingPortals
if #portals == 0 and trackingEnabled then
trackingCat = trackingCat.."[[Category:Pages with empty portal template]]"
end
end
return portals, trackingCat, errMsg
end
local function portalBox(args)
return mw.html.create('ul')
:attr('role', 'navigation')
:attr('aria-label', 'Portals')
:addClass('noprint')
:addClass(args.error and '' or 'portalbox')
:addClass(args.border and 'portalborder' or '')
:addClass(args.left and 'portalleft' or 'portalright')
:css('margin', args.margin or nil)
:newline()
end
local function fillBox(root, contents)
for _, item in ipairs(contents) do
local entry = root:tag('li')
entry:addClass('portalbox-entry')
local image = entry:tag('span')
image:addClass('portalbox-image')
image:wikitext(item[1])
local link = entry:tag('span')
link:addClass('portalbox-link')
link:wikitext(item[2])
end
return root
end
local function noviewer(portalImage)
local portalImage, hasClass = mw.ustring.gsub(portalImage, "class%s*=[^%|]+", "%0 noviewer")
if hasClass == 0 then
portalImage = portalImage.."|class=noviewer"
end
return portalImage
end
function p._portal(portals, args)
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,border=true}) do
if args[key] == nil then args[key] = default end
args[key] = yesno(args[key], default)
end
local root = portalBox(args)
local trackingCat = ''
local errMsg = nil
args.minPortals = args.nominimum and 0 or 1
args.maxPortals = -1
portals, trackingCat, errMsg = p._checkPortals(portals, args)
root:wikitext(trackingCat)
if errMsg then
if args.border then
args.error = true
root = portalBox(args)
root:wikitext(trackingCat)
local errTag = root:tag('strong')
errTag:addClass('error')
errTag:css('padding','0.2em')
errTag:wikitext('Error: '..errMsg)
end
return tostring(root)
end
if #portals == 0 then
return trackingCat
end
local contents = {}
local defaultUsed = nil
for _, portal in ipairs(portals) do
local portalImage = getImageName(portal)
if portalImage == defaultImage then
defaultUsed = portal
else
portalImage = noviewer(portalImage)
end
local image = string.format('[[File:%s|32x28px]]',
portalImage)
local link = string.format('[[Portal:%s|%s%sportal]]',
portal, portal, args.addBreak and '<br />' or ' ')
table.insert(contents, {image, link})
end
if defaultUsed and args.tracking and checkTracking() then
local cat = string.format('[[Category:Portal templates with default image|%s]]',
defaultUsed)
root:wikitext(cat)
end
return tostring(fillBox(root, contents))
end
function p._demo(imageList, args)
for key, default in pairs({left=false,border=true}) do
if args[key] == nil then args[key] = default end
args[key] = yesno(args[key], default)
end
local root = portalBox(args)
local contents = {}
for _, fn in ipairs(imageList) do
local image = string.format('[[File:%s|32x28px]]',noviewer(fn))
local link = string.format('[[:File:%s|%s]]',fn,fn)
table.insert(contents,{image,link})
end
return tostring(fillBox(root,contents))
end
function p._image(portal,keep)
if type(portal) == 'table' then
portal = portal[1]
end
local name = getImageName(portal)
local keepargs = yesno(keep)
if keepargs then
return noviewer(name)
end
local args = mw.text.split(name, "|", true)
local result = {args[1]}
local category = ''
for i = 2,#args do
local m = mw.ustring.match(args[i], "^%s*category%s*=")
if m then
table.insert(result, args[i])
end
end
return table.concat(result,"|")
end
local function getAllImageTable()
local images = {}
for portal, image in pairs(imageData.images) do
local args = mw.text.split(image,"|", true)
images[portal] = args[1]
end
return images
end
function p._displayAll(portals, args)
local lang = mw.language.getContentLanguage()
portals = portals or {}
for portal in pairs(getAllImageTable()) do
table.insert(portals,lang:ucfirst(portal))
end
table.sort(portals)
args.redlinks = args.redlinks or "yes"
return p._portal(portals, args)
end
function p._imageDupes()
local exists, dupes = {}, {}
for portal, image in pairs(getAllImageTable()) do
if not exists[image] then
exists[image] = portal
else
table.insert(dupes, string.format('The image "[[:File:%s|%s]]" is used for both portals "%s" and "%s".', image, image, exists[image], portal))
end
end
if #dupes < 1 then
return 'No duplicate images found.'
else
return 'The following duplicate images were found:\n* ' .. table.concat(dupes, '\n* ')
end
end
local function processPortalArgs(args)
args = type(args) == 'table' and args or {}
local portals = {}
local namedArgs = {}
for k, v in pairs(args) do
if type(k) == 'number' and type(v) == 'string' then
table.insert(portals, k)
elseif type(k) ~= 'number' then
namedArgs[k] = v
end
end
table.sort(portals)
for i, v in ipairs(portals) do
portals[i] = args[v]
end
return portals, namedArgs
end
function p._processPortalArgs(args)
return processPortalArgs(args)
end
function p.image(frame)
local origArgs = getArgs(frame)
local portals, args = processPortalArgs(origArgs)
return p._image(portals[1],args.border)
end
function p.demo(frame)
local args = getArgs(frame)
local styles = frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles} }
return styles..p._demo(args,args)
end
local function makeWrapper(funcName)
return function (frame)
local origArgs = getArgs(frame)
local portals, args = processPortalArgs(origArgs)
local results = ''
if funcName == '_portal' or funcName == '_displayAll' then
results = frame:extensionTag{ name = 'templatestyles', args = { src = templatestyles} }
end
return results .. p[funcName](portals, args)
end
end
for _, funcName in ipairs{'portal', 'imageDupes', 'displayAll'} do
p[funcName] = makeWrapper('_' .. funcName)
end
return p
