Module:FileInfo
Jump to navigation
Jump to search
This is the main module for the following templates:
local p = {}
local h = {}
local Data = mw.loadData("Module:FileInfo/Data")
-- It's important to minimize the number of imports because this module is linked on every file page
-- Any change to these modules will trigger a large MediWiki job queue
local Franchise = require("Module:Franchise")
local Util = {
args = {
parse = require("Module:Util/args/parse")
},
pages = {
exists = require("Module:Util/pages/exists")
},
}
local MAX_IMAGE_AREA = require("Module:Constants/number/maxImageArea")
function h.warn(msg, details)
local Error = require("Module:Error")
return Error.warning(msg, details)
end
function p.StoreWidth(frame)
return mw.title.getCurrentTitle().file.width
end
function p.StoreHeight(frame)
return mw.title.getCurrentTitle().file.height
end
function p.Main(frame)
local args = frame:getParent().args
local args = h.preformat(args)
local args, err = Util.args.parse(args, p.Templates.FileInfo)
local result = h.printFileInfoTable(frame, args)
local categories = h.categories(args.type, args.game, args.subject)
-- Avoid categories from being added to [[MediaWiki:Upload-default-description]] and [[MediaWiki:Msu-comment]]
if mw.title.getCurrentTitle().nsText == "MediaWiki" then
return result, err
end
return categories, result, err -- categories first in case there's notices attached to them - see h.maintenanceCategories()
end
function h.printFileInfoTable(frame, args)
local gameDisplay
if args.game and args.game ~= "N/A" then
local gameLogo = Franchise.logo(args.game)
local gameImage = gameLogo and gameLogo ~= "" and string.format("[[%s|130x130px]]", gameLogo)
local gameLink = Franchise.link(args.game)
local gameText = gameLink and string.format("This is a file pertaining to %s.", gameLink)
if gameImage and gameText then
gameDisplay = gameImage .. " " .. gameText
elseif gameText then
gameDisplay = gameText
else
local err = h.warn(string.format("Invalid game code <code>%s</code>", args.game), "See [[:Category:Franchise codes]] for accepted codes.")
local cat = require("Module:Constants/category/invalidArgs")
gameDisplay = err.."[[Category:"..cat.."]]"
end
end
local type = args.type and Data.types[args.type]
local typeLink = type and type.category and string.format("[[:Category:%s|%s]]", type.category, args.type)
local license
if args.licensing and h.licenseExists(args.licensing) then
license = frame:expandTemplate({
title = "FileInfo/License/" .. args.licensing,
args = {
trademark = args.trademark
}
})
else
license = frame:expandTemplate({ title = "FileInfo/License/Unsure" })
end
local html = mw.html.create("table"):addClass("wikitable fileinfo")
h.row(html, "Summary", args.summary)
h.row(html, "Type", typeLink)
h.row(html, "Source", args.source or frame:expandTemplate({ title = "No Source" }))
h.row(html, "Game", gameDisplay)
h.row(html, "Licensing", license, {
rowspan = args.trademark and "2" or "1"
})
h.row(html, "Trademark", args.trademark and frame:expandTemplate({ title = "FileInfo/License/Trademark" }))
return tostring(html)
end
function h.row(html, field, value, attributes)
if value then
return html
:tag("tr")
:tag("th")
:wikitext(field)
:done()
:tag("td")
:wikitext(value)
:done()
:done()
end
end
function h.categories(type, game, subjects)
local categories = ""
categories = categories..h.gameTypeCategories(game, type)
categories = categories..h.subjectCategories(subjects)
categories = categories..h.maintenanceCategories(type)
return categories
end
function h.gameTypeCategories(game, type)
local categories = ""
local gameName = game and game ~= "N/A" and Franchise.shortName(game)
local typeCat = type and Data.types[type] and Data.types[type].category
local gameRequired = type and Data.types[type] and Data.types[type].gameRequired
if typeCat and gameName and game ~= "Series" then
categories = categories..string.format("[[Category:%s %s]]", gameName, typeCat)
elseif typeCat then
categories = categories..string.format("[[Category:%s]]", typeCat)
elseif gameCat then
categories = categories..string.format("[[Category:%s Files]]", gameName)
end
if game == "N/A" then
categories = categories.."[[Category:Files with inapplicable game]]"
end
if type and gameRequired ~= false and not game then
local errMsg = string.format("<code>game</code> parameter is required for file type <code>%s</code>.", type)
local details = "For a list of accepted game values, see [[:Category:Franchise codes]]. If none of these values apply, set the <code>game</code> parameter to <code>N/A</code>."
categories = categories..h.warn(errMsg, details).."[[Category:Files lacking game info]]"
end
return categories
end
function h.subjectCategories(subjects)
if not subjects then
return ""
end
local Term = require("Module:Term")
local categories = ""
for i, subject in ipairs(subjects) do
local term, errCategories = Term.fetchTerm(subject, "Series")
if not term then
local utilsError = require("Module:UtilsError")
local utilsMarkup = require("Module:UtilsMarkup")
utilsError.warn(string.format("subject <code>%s</code> is not a valid [[Template:Term|term]]", subject))
categories = categories..utilsMarkup.categories(errCategories)
else
term = string.gsub(term, "#", "") -- strip # from term because categories can't have them in their name
-- only add subject-based categories if they already exist, to avoid spamming Special:WantedCategories
if Util.pages.exists("Category:Images of "..term) then
categories = categories.."[[Category:Images of "..term.."]]"
end
end
end
return categories
end
function h.maintenanceCategories(type)
local categories = ""
local frame = mw.getCurrentFrame()
local title = mw.title.getCurrentTitle()
local mimeType = title.file and title.file.mimeType
if type == "Sprite" and mimeType == "image/gif" then
categories = categories..frame:expandTemplate({ title = "FileInfo/Notices/GIF Sprite" })
end
local exceedsMaxImageArea = title.file and ((title.file.width or 0) * (title.file.height or 0)) > MAX_IMAGE_AREA
if mimeType ~= "image/jpeg" and exceedsMaxImageArea then
categories = categories..frame:expandTemplate({ title = "FileInfo/Notices/Oversized" })
end
-- See category page for why we do this ourselves instead of using Special:UnusedFiles
if title.nsText == "File" and h.isUnused(title.text) then
categories = categories..frame:expandTemplate({ title = "FileInfo/Notices/Unused" })
end
return categories
end
function h.isUnused(filename)
local separator = "$separator$"
local dplQuery = string.format("{{#dpl:|imageused=%s|count=2}}", filename, separator)
local dplResult = mw.getCurrentFrame():preprocess(dplQuery)
return dplResult == ""
end
-- For supporting types written in lower case or Title Case
-- Previously only the former was supported but editors had a tendency to use the latter
-- Which is understandable because the type category is in title case, Template:Media is in title case,
-- and all other fields in FileInfo are in title case or sentence case
-- We may eventually decide to support only Title Case but that would mean
-- running a text-replace on the thousands of file pages using lowercase
function h.preformat(args)
local _args = {}
for k, v in pairs(args) do
if k == "type" then
_args[k] = string.gsub(" "..v, "%W%l", string.upper):sub(2)
else
_args[k] = v
end
end
return _args
end
function h.licenseExists(license)
for i, definedLicense in ipairs(Data.licenses) do
if license == definedLicense then
return true
end
end
return false
end
function p.enumTypes()
local enum = {}
for k in pairs(Data.types) do
table.insert(enum, k)
end
enum.reference = "[[Module:FileInfo/Data]]"
return enum
end
function p.enumLicenses()
local enum = {}
for i, license in ipairs(Data.licenses) do
enum[i] = license
end
enum.reference = "[[Module:FileInfo/Data]]"
return enum
end
p.Templates = {
FileInfo = {
purpose = "Displays, categorizes, and stores file information. See [[Guidelines:Files]] for further guidance.",
format = "block",
paramOrder = {"summary", "type", "source", "game", "licensing", "subject", "trademark"},
boilerplate = {
tabs = {
{
label = "Zelda-Related Files",
params = {"summary", "type", "source", "game", "licensing", "subject"},
},
{
label = "Other Files",
params = {"summary", "type", "source", "licensing"},
},
{
label = "All Parameters",
params = {"summary", "type", "source", "game", "licensing", "subject", "trademark"},
},
},
},
params = {
summary = {
--required = true,
type = "content",
desc = "A short description of the file.",
trim = true,
nilIfEmpty = true,
},
type = {
required = "Category:Files lacking type info",
type = "string",
desc = "The type of file, which determines how it is [[:Category:Files by Type|categorized]].",
enum = p.enumTypes(),
trim = true,
nilIfEmpty = true,
},
source = {
required = "Category:Files Lacking Sources",
type = "string",
desc = "The original source of the file. It may be in the form of a URL or author recognition. [[Template:Source]] exists for this purpose.",
trim = true,
nilIfEmpty = true,
},
subject = {
type = "string",
desc = "Wiki article names of all the subjects depicted in the file. A comma-separated list.",
split = true,
trim = true,
nilIfEmpty = true,
},
game = {
--required = true,
type = "string",
desc = "<p>A valid [[:Category:Franchise codes|franchise code]] for a game, book, comic, manga, or TV show (or <code>Series</code>).</p>"
.."<p>Required for game-based types such as <code>Artwork</code>, <code>Screenshot</code>, <code>Sprite</code>, etc. See [[Module:FileInfo/Data]] for full list.</p>"
.."<p><code>game</code> can be set to <code>N/A</code> when a game is required for the type but no franchise code applies, namely for images of [[The Legend of Zelda in Popular Culture|unlicensed media]].",
trim = true,
nilIfEmpty = true,
},
licensing = {
required = "Category:Unlicensed Files",
type = "string",
desc = "The copyright licensing for the file. For the vast majority of files, <code>Copyright</code> is the correct value here.",
enum = p.enumLicenses(),
trim = true,
nilIfEmpty = true,
},
trademark = {
type = "boolean",
desc = "Enter any text to add a trademark notice to the licensing. Use on all [[:Category:Trademarks|trademarks]] (usually denoted by an ® or ™ symbol).",
trim = true,
nilIfEmpty = true,
}
}
}
}
return p