Module:File

local p = {} local h = {}

local Franchise = require("Module:Franchise") local Term = require("Module:Term") local utilsArg = require("Module:UtilsArg") local utilsLayout = require("Module:UtilsLayout") local utilsMarkup = require("Module:UtilsMarkup") local utilsPage = require("Module:UtilsPage") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable")

local data = mw.loadData("Module:File/Data")

-- Template:FileInfo function p.StoreWidth(frame) return mw.title.getCurrentTitle.file.width end function p.StoreHeight(frame) return mw.title.getCurrentTitle.file.height end function p.FileInfo(frame) local args, err = utilsArg.parse(frame:getParent.args, p.Templates.FileInfo) local result = p.printFileInfo(args) if err then return result .. utilsMarkup.categories(err.categories) else return result end end function p.printFileInfo(args) return h.printFileInfoTable(args) .. h.categories(args.type, args.game, args.subject) end function h.printFileInfoTable(args) local gameDisplay if args.game then local gameLogo = Franchise.logo(args.game) local gameImage = gameLogo and utilsPage.exists(gameLogo) and utilsMarkup.file(gameLogo, { size = "130px" }) 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 gameDisplay = "" end end local type = args.type and data.typesByKey[args.type] type = type and type.cat

local license if args.licensing and utilsTable.includes(data.licenses, args.licensing) then license = mw.getCurrentFrame:expandTemplate({			title = "FileInfo/" .. args.licensing,			args = {				trademark = args.trademark			}		}) else license = mw.getCurrentFrame:expandTemplate({ title = "FileInfo/Unsure" }) end

local html = mw.html.create("table"):addClass("wikitable fileinfo") h.row(html, "Summary", args.summary) h.row(html, "Type", type) h.row(html, "Source", args.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 mw.getCurrentFrame:expandTemplate({ title = "FileInfo/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 gameName = game and Franchise.shortName(game) local typeCat = type and data.typesByKey[type] and data.typesByKey[type].cat local categories = {} if typeCat and not typeCat.nogame and gameName and game ~= "Series" then table.insert(categories, gameName .. " " .. typeCat) elseif typeCat then table.insert(categories, typeCat) elseif gameCat then table.insert(categories, gameName .. " Files") end if subjects then categories = utilsTable.concat(categories, h.subjectCategories(subjects, game)) end return utilsMarkup.categories(categories) end function h.subjectCategories(subjects, game) local categories = utilsTable.flatMap(subjects, function(subject)		local term, err = Term.fetchTerm(subject, game)		if not term then			return err.categories -- add term-related maintenance categories, if any		end		term = string.gsub(term, "#", "") -- strip # from term because categories can't have them in their name		local category = "Images of "..term		 -- only add subject-based categories if they already exist, to avoid spamming Special:WantedCategories		if utilsPage.exists("Category:" .. category) then			return {category}		else			return {}		end	end) return categories end

-- Module:File/Data function p.Data(frame) local result = "" result = result .. utilsMarkup.heading(2, "Types") result = result .. utilsLayout.table({		sortable = true,		headers = {"Type", "Category"},		rows = utilsTable.map(data.types, function(type) local key = utilsMarkup.code(type.key) local cat = "Category:"..type.cat.."" return {key, cat} end)	}) result = result .. utilsMarkup.heading(2, "Licenses") result = result .. utilsLayout.table({		sortable = true,		headers = {"License", "Template", "Output"},		rows = utilsTable.map(data.licenses, function(license) local template = "FileInfo/"..license local templateLink = "Template:"..template.."" local templateOutput = mw.getCurrentFrame:expandTemplate({title = template}) return {utilsMarkup.code(license), templateLink, templateOutput} end)	})

return result end

-- Various templates function p.Icon(frame) local args = frame.args return p.icon(args[1], args[2], {		size = args.size	}) end

-- Utilities function p.gameImage(game, subject, type, options) local parts = utilsTable._filter(utilsString.notEmpty)({game, subject, type}) local filename = table.concat(parts, " ") .. ".png" return p.image(filename, options) end

function p.icon(game, subject, options) local type = "Icon" if Franchise.graphics(game) == "2D" then type = "Sprite" end return p.gameImage(game, subject, type, options) end

function p.image(filename, options) filename = utilsPage.stripNamespace(filename) if utilsPage.exists("File:" .. filename) then return utilsMarkup.file(filename, options), true end local uploadUrl = mw.uri.fullUrl("Special:Upload") uploadUrl:extend({		wpDestFile = filename	}) local options = utilsTable.merge({}, options, {		link = tostring(uploadUrl)	})

-- Make sure thumbnail for 'no image' is no less than 100x100px local size for dimension in string.gmatch(options.size or "", "[0-9]+") do		if tonumber(dimension) < 100 then size = "100px" end end options.size = size or options.size or "100px" return utilsMarkup.file("File:No Image Upload.png", options), false end

function p.logo(code, options) local filename = Franchise.logo(code) return p.image(filename, options) end

p.Templates = { FileInfo = { purpose = "Displays, categorizes, and stores file information. See Guidelines:Files for further guidance.", format = "block", paramOrder = {"summary", "subject", "type", "source", "game", "licensing", "trademark"}, params = { summary = { --required = true, type = "content", desc = "A short description of the file.", trim = true, nilIfEmpty = true, },			type = { required = "Category:Files Lacking Type", type = "string", desc = "The type of file, which determines how it is categorized.", enum = data.typesEnum, 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 = "A valid code for a game, book, comic, manga, or TV show (or ).", enum = Franchise.enum({ 					includeSeries = true,					includeGroups = true,				}), trim = true, nilIfEmpty = true, },			licensing = { required = "Category:Unlicensed Files", type = "string", desc = "The copyright licensing for the file. For the vast majority of files,  is the correct value here.", enum = data.licenses, trim = true, nilIfEmpty = true, },			trademark = { type = "boolean", desc = "Enter any text to add a trademark notice to the licensing. Use on all trademarks (usually denoted by an ® or ™ symbol).", trim = true, nilIfEmpty = true, }		},		examples = { vertical = true, {				summary = "LADX:", subject = "Animal Village, Rabbit", type = "map", source = "", game = "LADX", licensing = "Copyright", },			{				summary = "The Timeline", source = "", type = "print", game = "Series", licensing = "Copyright" },			{				summary = "Nintendo's current logo.", type = "logo", source = "", licensing = "PD-Simple", trademark = "yes", },			{				summary = "File missing required info" },		},	} }

local optionsSchema = { type = "record", properties = { {			name = "size", type = "string", desc = "Image size in pixels.", },		{			name = "link", type = "string", desc = "Name of a page on the wiki or an external URL for the image thumbnail to link to.", },		{			name = "caption", type = "string", desc = "Alt text for the image.", },	} } local franchiseCode = { required = true, type = "string", desc = "A franchise code." }

p.Schemas = { image = { filename = { required = true, type = "string", desc = "Filename of the image, with or without the namespace prefix.", },		options = optionsSchema, },	gameImage = { game = franchiseCode, subject = { type = "string", required = true, },		type = { type = "string", required = true, enum = {"", "Artwork", "Icon", "Model", "Render", "Screenshot", "Sprite", "Texture"}, },		options = optionsSchema, },	icon = { game = franchiseCode, subject = { type = "string", required = true, },		options = optionsSchema, },	logo = { code = franchiseCode, optons = optionsSchema, }, }

p.Documentation = { image = { desc = "A higher-level version of utilsMarkup.file with awareness of whether the file exists or not.", params = {"filename", "options"}, returns = { "Wikitext rendering an image thumbnail.", "A boolean — true if the image exists, false otherwise.", },		cases = { {				args = {"File:TWW Great Fairy Figurine Model.png", { link = "Great Fairy", size = "100px" }},				expect = {"", true} },			{				desc = "If file does not exist, show 'click to upload' thumbnail which links to Special:Upload.", args = {"File:TWWHD Great Fairy Figurine Model.png", { link = "Great Fairy", size = "150px", }},				expect = {"", false} },			{				desc = "'No image' thumbnail has minimum 100px width, because it is illegible at smaller sizes.", args = {"File:TWWHD Great Fairy Figurine Model.png", { size = "64px", }},				expect = {"", false}, },		},	},	gameImage = { desc = "A specialized version of image that infers the filename from game, subject, and type.", params = {"game", "subject", "type", "options"}, returns = { "A  of wikitext that renders a thumbnail.", "A boolean — true if the image exists, false otherwise.", },		cases = { {				args = {"TWW", "Great Fairy Figurine", "Model", { link = "Great Fairy", size = "100px" }},				expect = {"", true} },		}	},	icon = { params = {"game", "subject", "options"}, returns = "An icon thumbnail for the subject in the given game.", cases = { {				args = {"LANS", "Pineapple"}, expect = "" },			{				args = {"LADX", "Pineapple"}, expect = "" },		}	},	logo = { params = {"code", "options"}, returns = { "Given a valid franchise code, returns a logo thumbnail.", "A boolean indicating whether a logo exists for the game yet.", },		cases = { {				args = {"LANS", { size = "200px" }}, expect = {"", true} },			{				args = {"SSB4", { size = "200px" }}, expect = {"", true}, },			{				args = {"SS (Himekawa)", { size = "200px" }}, expect = {"", true} },			{				args = {"TLoZ (Mishouzaki)", { size = "200px" }}, expect = {"", true}, },			{				args = {"TAoL (Mishouzaki)", { size = "200px" }}, expect = {"", false}, },			{				args = {"E", { size = "200px" }}, expect = {"", true}, },			{				args = {"TMoL", { size = "200px" }}, expect = {"", true}, },		}	} }

return p