Module:Icon
Appearance
Documentation for this module may be created at Module:Icon/doc
--- A library that other modules can use to create icon images with automatic prefix/suffix settings for items, characters, and weapons.
-- (Other icon types must have their types/suffixes specified manually.)
--
-- '''Note:''' this module is (currently) NOT related to [[Template:Icon]].
--
-- @script Icon
local TemplateData = require('Module:TemplateData')
local p = {}
local FOOD_PREFIXES = {
['Suspicious '] = 1,
['Delicious '] = 1,
}
-- icon arg defaults for template data
-- uses list format to ensure that the order is the same when added to another list of args using `p.addIconArgs`
local ICON_ARGS = {
{name='name',
label='Name',
description='The name of the {labelPrefix}image.',
example={'Furnishing Blueprint', 'Fruit Paste Bait', 'Anemo'}
},
{name='link', displayType='wiki-page-name', defaultFrom='name',
label='Link',
description='The page that the {labelPrefix}image links to.'
},
{name='extension', alias='ext', default='png',
label='File Extension',
description='The file extension for the {labelPrefix}image.',
example={'png', 'jpg', 'jpeg', 'gif'},
},
{name='type', displayDefault='determined based on {labelPrefix}Name; "Item" if unknown',
label='File Prefix',
description='The file prefix to prepend to {labelPrefix}Name.',
example={'Item', 'Weapon', 'Character', 'Icon'}
},
{name='suffix', displayDefault='determined based on {labelPrefix}Name/{labelPrefix}Type',
label='File Suffix',
description='The file suffix to append to {labelPrefix}Name.',
example={'Icon', 'Thumb', '2nd', 'White'}
},
{name='size', default='20',
label='Size',
description='The height and width of the {labelPrefix}image in pixels. A single number will be used for both height and width; to specify them separately, use \'wxh\' format.',
example={'20', '20x10', '20x', 'x20'}
},
{name='alt', defaultFrom='name', displayDefault='determined based on {labelPrefix}Name, and updated based on {labelPrefix}Character Outfit and {labelPrefix}Weapon Ascension Phase',
label='Alt Text',
description='The alt text of the {labelPrefix}image.',
},
{name='outfit', alias='o',
label='Character Outfit',
description='Name of the Outfit equipped on the character in the {labelPrefix}image. (Ignored if not a character.)',
example='Sea Breeze Dandelion'
},
{name='ascension', alias='a', type='number', default=0,
label='Weapon Ascension Phase',
description='Ascension Phase of the weapon in the {labelPrefix}image. (Weapon image changes for ascension 2 or higher. Ignored if not a weapon.)',
example={'1', '2'}
},
}
--- Returns a table version of the input.
-- @param v A table or an item that belongs in a table.
-- @return {table}
local function ensureTable(v)
if type(v) == 'table' then return v end
return {v}
end
--- A special constant that can be used as a value in the `overrides` parameter for `addIconArgs`
-- to disable the given base config or TemplateData key.
p.EXCLUDE = {};
--- Copy entries from b into a, excluding values that are `p.EXCLUDE`.
-- @param {table} a Table to insert into.
-- @param {table} b Table to copy from.
local function copyTable(a, b)
for k, v in pairs(b) do
if v == p.EXCLUDE then
v = nil
end
a[k] = v
end
end
--- A function that other modules can use to append Icon arguments to their template data.
-- @param {TemplateData#ArgumentConfigList} base The template data to append to.
-- If any configs have a `name` that matches an Icon argument's (with `namePrefix`)
-- and a property `placeholderFor` set to `'Module:Icon'`, then the
-- corresponding Icon argument will replace it instead of being appended.
-- (This allows argument order to be changed for [[Module:TemplateData]]'s
-- documentation generation.)
-- @param {string} namePrefix A string to prepend to all parameter names.
-- @param {string} labelPrefix A string to prepend to all parameter labels
-- (the names displayed in documentation).
-- @param {TemplateData#ArgumentConfigMap} overrides A table of overrides to configure the template data.
-- Keys should be parameter names, and values are tables of TemplateData
-- configuration objects to merge with the default configuration.
-- These configuration objects can use @{Icon.EXCLUDE} as values to disable
-- the corresponding default configuration key (e.g., to disable a default value
-- or alias without adding a new one).
function p.addIconArgs(baseConfigs, namePrefix, labelPrefix, overrides)
-- preprocessing: save position of each placeholder config
local argLocations = {}
for i, config in ipairs(baseConfigs) do
if config.placeholderFor == 'Module:Icon' then
argLocations[config.name] = i
end
end
-- main loop: prepend namePrefix and labelPrefix where needed
-- and add configs to baseConfigs
for _, config in ipairs(ICON_ARGS) do
local override = overrides[config.name]
if override ~= false and override ~= p.EXCLUDE then
local c = {}
copyTable(c, config)
c.name = namePrefix .. c.name
c.label = labelPrefix .. c.label
if c.defaultFrom then
c.defaultFrom = namePrefix .. c.defaultFrom
end
if c.alias then
local aliases = {}
for _, a in ipairs(ensureTable(c.alias)) do
table.insert(aliases, namePrefix .. a)
end
c.alias = aliases
end
if override then
copyTable(c, override)
end
if c.description then
c.description = c.description:gsub('{labelPrefix}', labelPrefix)
end
if c.displayDefault then
c.displayDefault = c.displayDefault:gsub('{labelPrefix}', labelPrefix)
end
local placeholderIndex = argLocations[c.name]
if placeholderIndex then
baseConfigs[placeholderIndex] = c
else
table.insert(baseConfigs, c)
end
end
end
end
local function extendTable(base, extra)
out = {}
setmetatable(out, {
__index = function(t, key)
-- be defensive: base or extra may be nil
local val
if base ~= nil then
val = base[key]
end
if val ~= nil then
return val
end
if extra ~= nil then
return extra[key]
end
return nil
end
})
return out
end
local neighbors = mw.loadData('Module:Card/neighbors')
local ALL_DATA = {-- list of {type, data} in the order that untyped items should get checked
{'Neighbor', neighbors},
{'Creature', mw.loadData('Module:Card/creatures')},
{'Dish', mw.loadData('Module:Card/dishes')},
{'Plant', mw.loadData('Module:Card/plants')},
{'Furniture', mw.loadData('Module:Card/furnitures')},
{'Outfit', mw.loadData('Module:Card/outfits')},
{'Item', extendTable(characters, mw.loadData('Module:Card/items'))} -- allow characters to be items
}
--- A basic image type with filename prefix/suffix support.
-- Extends @{TemplateData#TableWithDefaults} with image-related properties,
-- allowing default property values to be customized after creation.
--
-- Image objects are created by @{Icon.createIcon}.
-- Use @{Image:buildString} to convert to wikitext.
-- @type Image
local IMAGE_ARGS = {
size = {default=''},
name = {default='', alias=1},
prefix = {default=''},
prefixSeparator = {default=' '},
suffix = {default=''},
suffixSeparator = {default=' '},
extension = {default='png', alias='ext'},
link = {defaultFrom='name'},
alt = {defaultFrom='name'},
}
local function buildImageFullPrefix(img)
local prefix = img.prefix
if prefix ~= '' then
return prefix .. img.prefixSeparator
end
return ''
end
local function buildImageFullSuffix(img)
local suffix = img.suffix
if suffix ~= '' then
return img.suffixSeparator .. suffix
end
return ''
end
local function buildImageFilename(img)
if img.name == '' then return '' end
return 'File:' .. buildImageFullPrefix(img) .. img.name .. buildImageFullSuffix(img) .. '.' .. img.extension
end
local function buildImageSizeString(img)
local size = img.size
if size == nil or size == '' then
return ''
end
size = tostring(size)
if size:find('x', 1, true) then
return size .. 'px'
end
return size .. 'x' .. size .. 'px'
end
--[[
Returns wikitext that will display this image.
@return {string} Wikitext
@function Image:buildString
--]]
local function buildImageString(img)
local filename = buildImageFilename(img)
if filename == '' then return '' end
return '[[' .. filename .. '|' .. buildImageSizeString(img) .. '|link=' .. img.link .. '|alt=' .. img.alt .. ']]'
end
--[[
Creates an `Image` object with the given properties.
@param {table} args A table of `Image` properties that to assign to the new `Image`.
@see @{Image} for property documentation
@return {Image} The new `Image` object.
@constructor
--]]
local function createImage(args)
local out
if type(args) == 'table' then
out = TemplateData.processArgs(args, IMAGE_ARGS, {preserveDefaults=true})
else
out = {name = args}
end
-- add buildString function to image directly, not to image.nonDefaults
rawset(out, 'buildString', buildImageString)
return out
end
--- The name of the image. Used to determine filename.
-- @property {string} Image.name
--- Maximum image size using wiki image syntax.
-- Unlike regular wiki image syntax, a single number specifies both height and width.
-- @property {string} Image.size
--- Image file prefix.
-- @property {string} Image.prefix
--- Appended to `prefix` if `prefix` is not empty. Defaults to a single space.
-- @property[opt] {string} Image.prefixSeparator
--- Image file suffix.
-- @property {string} Image.suffix
--- Prepended to `suffix` if `suffix` is not empty. Defaults to a single space.
-- @property {string} Image.suffixSeparator
--- Image file extension. (Alias: `ext`.)
-- @property {string} Image.extension
--- Image link. Also sets title (hover tooltip). Defaults to `name`.
-- @property {string} Image.link
--- Image alt text. Defaults to `name`.
-- @property {string} Image.alt
--- A helper function for other modules to get icon args with a prefix from the given table.
-- @param {table} args A table containing icon args (and probably other args).
-- @param {string} prefix Prefix for keys to use when looking up entries from `args`.
-- If not specified, no prefix is used.
-- @return {table} A table containing only the extracted args, with the prefix removed from its keys.
function p.extractIconArgs(args, prefix)
prefix = prefix or ''
local out = TemplateData.createObjectWithDefaults()
for _, config in pairs(ICON_ARGS) do
out.defaults[config.name] = args.defaults[prefix .. config.name]
out.nonDefaults[config.name] = args.nonDefaults[prefix .. config.name]
end
return out
end
--- A helper function that removes one of the given prefixes from the given string.
-- @param {string} str The string from which to strip a prefix
-- @param {table} prefixes A table whose keys are the possible prefixes to strip from `str`
-- @return {string} The string with the prefix removed.
-- @return[opt] {string} The prefix that was removed, or `nil` if no prefix was found.
function p.stripPrefixes(str, prefixes)
for prefix, _ in pairs(prefixes) do
if string.sub(str, 1, string.len(prefix)) == prefix then
return string.sub(str, string.len(prefix) + 1), prefix
end
end
return str
end
--[[
The main entry point for other modules.
Creates and returns an Image object with the given arguments.
Infers `args.type` if `args.name` matches a known item/character/weapon.
@param {table} args Table containing the arguments:
@param[opt] {string} args.name The name of the image.
Used to determine file name and set the default link and alt text.
If not specified, the output `Image` will produce empty wikitext.
@param[opt] {string} args.link Image link. Also sets title (hover tooltip).
Defaults to `name`.
@param[opt] {string} args.extension (alias: `ext`) Image file extension.
Defaults to 'png'.
@param[opt] {string} args.type Image type. Used to determine file prefix and default file suffix.
If not specified, type will be inferred if `args.name`
is a known item; otherwise, defaults to 'Item'.
@param[opt] {string} args.suffix File suffix override.
@param[opt] {string} args.size Maximum image size using wiki image syntax.
Unlike regular wiki image syntax, specifying a single number will
set both height and width.
@param[opt] {string} args.alt Image alt text. Defaults to `args.name`, but
also changes with `args.outfit` or `args.ascension`.
@param[opt] {string} args.outfit Character outfit. Only applies to character images.
@param[opt] {number} args.ascension Weapon ascension level. Only applies to weapon images.
@param[opt] {string} prefix Prefix to use when looking up arguments in `args`.
@return {Image} The image for given arguments.
Use `Image:buildString()` to get the wikitext for the image.
@return {string} The image type.
@return {TableWithDefaults} Associated data for given item (e.g., rarity, display name).
--]]
function p.createIcon(args, prefix)
if prefix then
args = p.extractIconArgs(args, prefix)
end
args = TemplateData.processArgs(args, ICON_ARGS, {preserveDefaults=true})
local baseName, prefix = p.stripPrefixes(args.name or '', FOOD_PREFIXES)
-- determine type by checking for data
local image_type, data
for i, v in ipairs(ALL_DATA) do
image_type = v[1]
if args.type == nil or args.type == image_type then
data = v[2][baseName]
if data then break end
end
end
image_type = args.type or image_type -- in case args.type isn't in ALL_DATA (e.g., Enemy, Wildlife)
local image = createImage(args)
image.suffix = 'Icon'
image.defaults.suffix = 'Icon'
return image, image_type, data
end
return p