(use luacache.) |
(crap) |
||
(12 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
+ | ---Holds the tables with the l10n information for the different languages, taken from the l10n submodule. |
||
− | |||
− | ------- l10n info -------------- |
||
local l10n_info = mw.loadData('Module:Item/l10n') |
local l10n_info = mw.loadData('Module:Item/l10n') |
||
+ | ---Holds the l10n information for the current language, as key-value pairs. |
||
− | ------- The following is not related to l10n. -------------- |
||
⚫ | |||
+ | |||
+ | ---The current language. Determines which l10n table to use. |
||
⚫ | |||
local trim = mw.text.trim |
local trim = mw.text.trim |
||
Line 10: | Line 13: | ||
local cache = require 'mw.ext.LuaCache' |
local cache = require 'mw.ext.LuaCache' |
||
+ | local should_cache = true |
||
+ | |||
+ | ---A cached version of the current frame, the interface to the parser. |
||
local currentFrame |
local currentFrame |
||
+ | ---Holds the arguments from the template call. |
||
local args_table |
local args_table |
||
⚫ | |||
⚫ | |||
+ | |||
⚫ | |||
+ | ---Return the l10n string associated with the `key`. |
||
+ | ---@param key string |
||
+ | ---@return string |
||
⚫ | |||
return l10n_table[key] or l10n_info['en'][key] |
return l10n_table[key] or l10n_info['en'][key] |
||
end |
end |
||
+ | ---Return a trimmed version of the value of the template parameter with the specified `key`. |
||
⚫ | |||
+ | ---Return `nil` if the parameter is empty or unset. |
||
+ | ---@param key string|number |
||
+ | ---@return string|nil |
||
⚫ | |||
local value = args_table[key] |
local value = args_table[key] |
||
if not value then |
if not value then |
||
Line 31: | Line 44: | ||
end |
end |
||
+ | ---Convert a string of parameters in a `@param1:value^@param2:value^` format to a table. |
||
⚫ | |||
+ | ---Change the `name` and `text` parameters to `1` and `2`, respectively. |
||
+ | ---@param paramstr string |
||
+ | ---@return table |
||
⚫ | |||
local args = {} |
local args = {} |
||
− | for s in string.gmatch( |
+ | for s in string.gmatch(paramstr, '%b@^') do |
local k,v = string.match(s, '^@(.-):(.*)^$') |
local k,v = string.match(s, '^@(.-):(.*)^$') |
||
args[k] = v |
args[k] = v |
||
Line 42: | Line 59: | ||
end |
end |
||
+ | ---Split the `str` on each `div` in it and return the result as a table. |
||
− | -- credit: http://richard.warburton.it |
+ | ---Original version credit: http://richard.warburton.it. This version trims each substring. |
− | -- this version is with trim. |
||
+ | ---@param div string |
||
⚫ | |||
+ | ---@param str string |
||
+ | ---@return table|boolean |
||
⚫ | |||
if (div=='') then return false end |
if (div=='') then return false end |
||
local pos,arr = 0,{} |
local pos,arr = 0,{} |
||
Line 56: | Line 76: | ||
end |
end |
||
+ | ---Extract scale, width, and height from an input string. Up to two of the three can be empty in the input. |
||
+ | ---Example: `5x7px*0.75` → `0.75`, `5`, `7` |
||
+ | ---@param size string |
||
+ | ---@return string basescale |
||
+ | ---@return number width |
||
+ | ---@return number height |
||
local function parseSize(size) |
local function parseSize(size) |
||
if not size then return end |
if not size then return end |
||
Line 69: | Line 95: | ||
end |
end |
||
+ | ---Return width, height, and caching date for the specified `imagename` from the Imageinfo cargo table. |
||
⚫ | |||
+ | ---@param imagename string |
||
+ | ---@return number width |
||
+ | ---@return number height |
||
+ | ---@return string cached |
||
⚫ | |||
-- try to get from cargo cache |
-- try to get from cargo cache |
||
local result = mw.ext.cargo.query('Imageinfo', 'width, height, cached', { |
local result = mw.ext.cargo.query('Imageinfo', 'width, height, cached', { |
||
+ | -- escape apostrophes in the imagename input |
||
− | where = 'image='.. "'".. |
+ | where = 'image='.. "'"..imagename:gsub("'", "\\'"):gsub("'", "\\'").."'", |
orderBy = "cached DESC", |
orderBy = "cached DESC", |
||
limit = 1, |
limit = 1, |
||
Line 81: | Line 113: | ||
end |
end |
||
+ | ---Store width and height of the specified `imagename` to the Imageinfo cargo table and return them. |
||
⚫ | |||
+ | ---Width and height are computed via the `#imgw:` and `#imgh:` parser functions, respectively. |
||
− | local width, height |
||
+ | ---@param imagename string |
||
− | width = tonumber(currentFrame:callParserFunction( '#imgw', image)) |
||
+ | ---@return number width |
||
− | if width and width ~= 0 then -- save one expensive call when the file is not a valid image. |
||
+ | ---@return number height |
||
⚫ | |||
⚫ | |||
⚫ | |||
+ | -- don't cache {{item}}'s result when parsing imagesize fails. |
||
− | currentFrame:callParserFunction('#cargo_store:_table=Imageinfo',{ |
||
+ | should_cache = false |
||
⚫ | |||
+ | local imageTitle = mw.title.new("File:" .. imagename) |
||
⚫ | |||
+ | local width, height = imageTitle.file.width, imageTitle.file.height |
||
⚫ | |||
⚫ | |||
⚫ | |||
+ | should_cache = true -- ok, cache it. |
||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
⚫ | |||
end |
end |
||
return width, height |
return width, height |
||
end |
end |
||
+ | ---Retrieve the dimensions of the specified `image` from the Imageinfo cargo table. |
||
⚫ | |||
+ | ---If it doesn't have any data for the image yet, store it. |
||
⚫ | |||
+ | ---@param imagename string |
||
+ | ---@return number width |
||
+ | ---@return number height |
||
+ | local function getSizeInfo(imagename) |
||
⚫ | |||
-- cache missed, init cache |
-- cache missed, init cache |
||
if not cached then |
if not cached then |
||
− | width, height = storeInfoToCargo( |
+ | width, height = storeInfoToCargo(imagename) |
end |
end |
||
if width == 0 then width = nil end |
if width == 0 then width = nil end |
||
Line 109: | Line 151: | ||
end |
end |
||
− | + | ---Compute the final width and height of the image. |
|
+ | ---If necessary, retrieve data from or store data to the Imageinfo cargo table. |
||
+ | ---@param imagename string |
||
+ | ---@param width number |
||
+ | ---@param height number |
||
+ | ---@param scale number |
||
+ | ---@param maxwidth number |
||
+ | ---@param maxheight number |
||
+ | ---@return number width |
||
+ | ---@return number height |
||
+ | local function getImageSize(imagename, width, height, scale, maxwidth, maxheight) |
||
-- get size info from image file itself (may be expensive) |
-- get size info from image file itself (may be expensive) |
||
− | local w, h = getSizeInfo( |
+ | local w, h = getSizeInfo(imagename) -- store data to cache |
+ | -- if width and height are not given as input, but scale/maxwidth/maxheight are, then |
||
+ | -- set width and height to the original dimensions of the image |
||
if not width and not height and (scale or maxwidth or maxheight) then |
if not width and not height and (scale or maxwidth or maxheight) then |
||
width, height = w, h |
width, height = w, h |
||
Line 123: | Line 177: | ||
end |
end |
||
− | -- apply maxwidth/maxheight |
+ | -- apply maxwidth/maxheight |
if maxwidth then |
if maxwidth then |
||
if width then |
if width then |
||
Line 139: | Line 193: | ||
end |
end |
||
+ | -- round to natural numbers |
||
− | -- rounding |
||
if width then width = math.ceil(width) end |
if width then width = math.ceil(width) end |
||
if height then height = math.ceil(height) end |
if height then height = math.ceil(height) end |
||
Line 146: | Line 200: | ||
end |
end |
||
+ | ---Extract width and height from an input string. |
||
+ | ---Example: `6x9px` → `6`, `9` |
||
+ | ---@param maxsize string |
||
+ | ---@return number maxwidth |
||
+ | ---@return number maxheight |
||
local function parseMaxSize(maxsize) |
local function parseMaxSize(maxsize) |
||
if not maxsize then return end |
if not maxsize then return end |
||
Line 155: | Line 214: | ||
end |
end |
||
+ | ---Assemble the final wikicode for an image. |
||
⚫ | |||
+ | ---@param imagename string |
||
⚫ | |||
+ | ---@param link string |
||
+ | ---@param text string |
||
+ | ---@param size string As accepted by the `[[File:` syntax, e.g. `5x7px*0.75`. |
||
+ | ---@param scale number This will be multiplied by the scale in `size`, if necessary. |
||
+ | ---@param maxsize string |
||
+ | ---@return string |
||
⚫ | |||
⚫ | |||
if size or scale or maxsize then |
if size or scale or maxsize then |
||
− | local basescale, width, height = parseSize(size) -- width,height: number or nil |
+ | local basescale, width, height = parseSize(size) -- width, height: number or nil (basescale is string!) |
− | scale = (tonumber(scale) or 1) * (tonumber(basescale) or 1) |
+ | scale = (tonumber(scale) or 1) * (tonumber(basescale) or 1) -- combine the scale parameter and scale from the size parameter |
if scale == 0 or scale == 1 then |
if scale == 0 or scale == 1 then |
||
scale = nil |
scale = nil |
||
end |
end |
||
local maxwidth, maxheight = parseMaxSize(maxsize) |
local maxwidth, maxheight = parseMaxSize(maxsize) |
||
− | width, height = getImageSize( |
+ | width, height = getImageSize(imagename, width, height, scale, maxwidth, maxheight) -- can be 0 |
if width or height then |
if width or height then |
||
− | + | image_output = image_output .. '|' .. (width or '') .. 'x' .. (height or '') .. 'px' |
|
⚫ | |||
⚫ | |||
end |
end |
||
− | else |
||
− | return image_output .. ']]' |
||
end |
end |
||
⚫ | |||
end |
end |
||
+ | ---Return the full `[[File:` wikicode for each image in the input (multiple are separated with `/`). |
||
+ | ---@param image string |
||
+ | ---@param link string |
||
+ | ---@param text string |
||
+ | ---@param size string |
||
+ | ---@param scale string |
||
+ | ---@param maxsize string |
||
+ | ---@return string |
||
⚫ | |||
⚫ | |||
− | |||
if not image:find('/') then |
if not image:find('/') then |
||
+ | -- there is only one image in the input |
||
return imagecode(image, link, text, size, scale, maxsize) |
return imagecode(image, link, text, size, scale, maxsize) |
||
end |
end |
||
+ | -- there are multiple images in the input, separated with a slash |
||
image = explode('/', image) |
image = explode('/', image) |
||
local result = '' |
local result = '' |
||
if size and size:find('/') then |
if size and size:find('/') then |
||
+ | -- there are multiple sizes in the size parameter |
||
− | size = explode('/', size) |
+ | size = explode('/', size) -- so turn it into a table |
− | for i, v in ipairs(image) do |
+ | for i, v in ipairs(image) do -- iterate over the images |
− | result = result .. imagecode(v, link, text, size[i], scale, maxsize) |
+ | result = result .. imagecode(v, link, text, size[i], scale, maxsize) -- create the wikicode (using the respective size) |
end |
end |
||
else |
else |
||
− | for i, v in ipairs(image) do |
+ | for i, v in ipairs(image) do -- iterate over the images |
− | result = result .. imagecode(v, link, text, size, scale, maxsize) |
+ | result = result .. imagecode(v, link, text, size, scale, maxsize) -- create the wikicode |
end |
end |
||
end |
end |
||
Line 197: | Line 271: | ||
end |
end |
||
+ | ---Return a string like `Internal Item ID: `, depending on the `_type`. |
||
⚫ | |||
+ | ---@param _type '"item"'|'"tile"'|'"wall"'|'"npc"'|'"mount"'|'"buff"'|'"projectile"'|'"armor"' |
||
+ | ---@return string |
||
⚫ | |||
local id_text |
local id_text |
||
if _type == 'item' then -- a shortcut for faster |
if _type == 'item' then -- a shortcut for faster |
||
Line 225: | Line 302: | ||
return { |
return { |
||
− | parse = parse, |
+ | parse = parse, |
go = function(frame, args) |
go = function(frame, args) |
||
-- cache? |
-- cache? |
||
if not args then |
if not args then |
||
− | local cached = cache.get(': |
+ | local cached = cache.get(':_item:' .. frame.args[1]) |
if cached then |
if cached then |
||
return cached |
return cached |
||
Line 243: | Line 320: | ||
local _arg1 = getArg(1) or '' |
local _arg1 = getArg(1) or '' |
||
local _nolink = getArg('nolink') |
local _nolink = getArg('nolink') |
||
− | local _link = _nolink and '' or getArg('link') or frame:expandTemplate{ title = 'tr', args = {_arg1, link='y', lang=lang} } -- now: |
+ | local _link = _nolink and '' or getArg('link') or frame:expandTemplate{ title = 'tr', args = {_arg1, link='y', lang=lang} } -- now: _link == '' means nolink |
local text = getArg(2) or '' |
local text = getArg(2) or '' |
||
+ | -- hovertext: {{tr|_arg1}} or text or _link (in that order) |
||
local hovertext |
local hovertext |
||
if _arg1 ~= '' then |
if _arg1 ~= '' then |
||
Line 256: | Line 334: | ||
end |
end |
||
+ | -- set output flags |
||
⚫ | |||
− | |||
local output_image, output_text, output_table = true, true, false |
local output_image, output_text, output_table = true, true, false |
||
local _mode = getArg('mode') |
local _mode = getArg('mode') |
||
Line 269: | Line 346: | ||
end |
end |
||
end |
end |
||
+ | |||
⚫ | |||
local image_output, text_output |
local image_output, text_output |
||
+ | -- get wikicode for the image(s) |
||
if output_image then |
if output_image then |
||
local image_arg = getArg('image') |
local image_arg = getArg('image') |
||
Line 291: | Line 371: | ||
image_output = '' |
image_output = '' |
||
end |
end |
||
+ | -- get wikicode for the text |
||
if output_text then |
if output_text then |
||
− | local _note, _note2, _showid, _id = getArg('note'), getArg('note2'), getArg('showid'), getArg('id') |
+ | local _note, _note2, _showid, _id, _icon = getArg('note'), getArg('note2'), getArg('showid'), getArg('id'), getArg('icons') -- get info from arguments |
+ | -- prepare: display ID? |
||
if _id and not _showid then |
if _id and not _showid then |
||
_showid = true |
_showid = true |
||
Line 301: | Line 383: | ||
end |
end |
||
+ | -- prepare: wrap? |
||
local _wrap |
local _wrap |
||
if _showid or _note2 then |
if _showid or _note2 then |
||
Line 308: | Line 391: | ||
end |
end |
||
+ | -- prepare: link and display text |
||
if _link ~= '' then |
if _link ~= '' then |
||
if text == _link then |
if text == _link then |
||
Line 318: | Line 402: | ||
end |
end |
||
+ | -- prepare: eicons |
||
− | local |
+ | local icon = nil |
if _icon == 'n' or _icon == 'no' or _icon == 'off' then |
if _icon == 'n' or _icon == 'no' or _icon == 'off' then |
||
icon = '' |
icon = '' |
||
Line 325: | Line 410: | ||
end |
end |
||
+ | -- assemble HTML code |
||
local content = text -- item name link text first. |
local content = text -- item name link text first. |
||
-- '-w' class means 'wrapmode', optimized for multiple lines of text. But it should be disabled for single line text. |
-- '-w' class means 'wrapmode', optimized for multiple lines of text. But it should be disabled for single line text. |
||
Line 333: | Line 419: | ||
content = content .. icon |
content = content .. icon |
||
end |
end |
||
− | -- note in |
+ | -- note in a new line |
if _note then |
if _note then |
||
class = class .. ' -w' |
class = class .. ' -w' |
||
Line 339: | Line 425: | ||
end |
end |
||
else |
else |
||
− | -- note |
+ | -- note in the same line |
if _note then |
if _note then |
||
content = content .. '<span class="note">' .. _note .. '</span>' |
content = content .. '<span class="note">' .. _note .. '</span>' |
||
end |
end |
||
+ | -- eicons in the same line |
||
if icon ~= '' then |
if icon ~= '' then |
||
content = content .. icon |
content = content .. icon |
||
end |
end |
||
+ | -- note2 in a new line |
||
if _note2 then |
if _note2 then |
||
class = class .. ' -w' |
class = class .. ' -w' |
||
content = content .. '<div class="note">' .. _note2 .. '</div>' |
content = content .. '<div class="note">' .. _note2 .. '</div>' |
||
end |
end |
||
+ | -- id in a new line |
||
if _showid then |
if _showid then |
||
class = class .. ' -w' |
class = class .. ' -w' |
||
− | local idtype = (getArg('type') or 'item'):lower() |
+ | local idtype = (getArg('type') or 'item'):lower() |
if not _id then |
if not _id then |
||
+ | -- get ID automatically via {{itemIdFromName}} or the like |
||
_id = frame:expandTemplate{ title = idtype .. 'IdFromName', args = {_arg1} } |
_id = frame:expandTemplate{ title = idtype .. 'IdFromName', args = {_arg1} } |
||
end |
end |
||
Line 365: | Line 455: | ||
end |
end |
||
+ | -- handle custom CSS |
||
local _class, _css = getArg('class'), getArg('css') |
local _class, _css = getArg('class'), getArg('css') |
||
if _class then |
if _class then |
||
− | class = class .. ' ' .. _class |
+ | class = class .. ' ' .. _class -- add to existing classes |
end |
end |
||
local attr = {class = class} |
local attr = {class = class} |
||
if _css then |
if _css then |
||
− | attr.style = _css |
+ | attr.style = _css -- set the style attribute to parameter value |
⚫ | |||
− | |||
− | if getArg('anchor') then |
||
− | text_output = text_output .. '<div class="anchor" id="' .. frame:callParserFunction('anchorencode', _arg1) .. '"></div>' |
||
end |
end |
||
local return_string |
local return_string |
||
if output_table then |
if output_table then |
||
+ | -- table output |
||
attr.class = class |
attr.class = class |
||
− | local |
+ | local _rowspan = getArg('rowspan') |
+ | local rowspan_text = (_rowspan and (' rowspan=' .. _rowspan) or '') |
||
− | return_string = (rowspan and (' rowspan='..rowspan..' class="il1c" | ') or ' class="il1c" | ') .. mw.text.tag('span', attr, image_output) .. ' || class="il2c"'.. (rowspan and (' rowspan='..rowspan) or '')..' | ' .. mw.text.tag('span', attr, text_output) |
||
+ | -- prepare the two cells |
||
+ | local first_cell_pre = rowspan_text .. ' class="il1c"' |
||
+ | local first_cell_content = mw.text.tag('span', attr, image_output) |
||
+ | local second_cell_pre = rowspan_text .. ' class="il2c"' |
||
+ | local second_cell_content = mw.text.tag('span', attr, text_output) |
||
+ | -- combine |
||
+ | return_string = first_cell_pre .. " | " .. first_cell_content .. " || " .. second_cell_pre .. " | " .. second_cell_content |
||
else |
else |
||
+ | -- non-table output (text/image) |
||
return_string = mw.text.tag('span', attr, image_output .. text_output) |
return_string = mw.text.tag('span', attr, image_output .. text_output) |
||
end |
end |
||
+ | |||
− | --cache: |
||
+ | -- cache output for later reuse |
||
− | if not args then |
+ | if not args and should_cache then |
− | cache.set(': |
+ | cache.set(':_item:' .. frame.args[1], return_string, 3600*24) -- cache for 24 hours |
end |
end |
||
+ | |||
+ | -- output |
||
return return_string |
return return_string |
||
+ | |||
end, |
end, |
||
+ | |||
− | |||
⚫ | |||
+ | cache.delete(':_item:' .. frame.args[1]) -- delete that cache key. |
||
⚫ | |||
+ | |||
+ | storeImageInfo = function(frame) |
||
+ | currentFrame = frame |
||
+ | local width, height = storeInfoToCargo(frame.args[1]) |
||
+ | if not width or width == 0 or not height or height == 0 then |
||
+ | return |
||
⚫ | |||
+ | return frame:callParserFunction{name = "#dplvar:set", args = { |
||
+ | "_image_exist", "1", |
||
+ | "_image_width", width, |
||
+ | "_image_height", height, |
||
+ | }} |
||
⚫ | |||
+ | end, |
||
+ | |||
} |
} |
Revision as of 19:22, 28 August 2021
Documentation The documentation below is transcluded from Module:Item/doc. (edit | history)
This module is intended to provide functionality to the {{item}} template.
---Holds the tables with the l10n information for the different languages, taken from the l10n submodule.
local l10n_info = mw.loadData('Module:Item/l10n')
---Holds the l10n information for the current language, as key-value pairs.
local l10n_table
---The current language. Determines which l10n table to use.
local lang
local trim = mw.text.trim
local cargo = mw.ext.cargo
local eicons = require('Module:Exclusive').simpleEicons
local cache = require 'mw.ext.LuaCache'
local should_cache = true
---A cached version of the current frame, the interface to the parser.
local currentFrame
---Holds the arguments from the template call.
local args_table
---Return the l10n string associated with the `key`.
---@param key string
---@return string
local function l10n(key)
return l10n_table[key] or l10n_info['en'][key]
end
---Return a trimmed version of the value of the template parameter with the specified `key`.
---Return `nil` if the parameter is empty or unset.
---@param key string|number
---@return string|nil
local function getArg(key)
local value = args_table[key]
if not value then
return nil
end
value = trim(value)
if value == '' then
return nil
end
return value
end
---Convert a string of parameters in a `@param1:value^@param2:value^` format to a table.
---Change the `name` and `text` parameters to `1` and `2`, respectively.
---@param paramstr string
---@return table
local function parse(paramstr)
local args = {}
for s in string.gmatch(paramstr, '%b@^') do
local k,v = string.match(s, '^@(.-):(.*)^$')
args[k] = v
end
args[1] = args['name']
args[2] = args['text']
return args
end
---Split the `str` on each `div` in it and return the result as a table.
---Original version credit: http://richard.warburton.it. This version trims each substring.
---@param div string
---@param str string
---@return table|boolean
local function explode(div,str)
if (div=='') then return false end
local pos,arr = 0,{}
-- for each divider found
for st,sp in function() return string.find(str,div,pos,true) end do
arr[#arr + 1] = trim(string.sub(str,pos,st-1)) -- Attach chars left of current divider
pos = sp + 1 -- Jump past current divider
end
arr[#arr + 1] = trim(string.sub(str,pos)) -- Attach chars right of last divider
return arr
end
---Extract scale, width, and height from an input string. Up to two of the three can be empty in the input.
---Example: `5x7px*0.75` → `0.75`, `5`, `7`
---@param size string
---@return string basescale
---@return number width
---@return number height
local function parseSize(size)
if not size then return end
local basescale, width, height
size, basescale = unpack(explode('*', size))
if size ~= '' then
width, height = unpack(explode('x', string.gsub(size, 'px', '')))
width, height = tonumber(width), tonumber(height)
if width == 0 then width = nil end
if height == 0 then height = nil end
end
return basescale, width, height
end
---Return width, height, and caching date for the specified `imagename` from the Imageinfo cargo table.
---@param imagename string
---@return number width
---@return number height
---@return string cached
local function getInfoFromCargo(imagename)
-- try to get from cargo cache
local result = mw.ext.cargo.query('Imageinfo', 'width, height, cached', {
-- escape apostrophes in the imagename input
where = 'image='.. "'"..imagename:gsub("'", "\\'"):gsub("'", "\\'").."'",
orderBy = "cached DESC",
limit = 1,
})
for _, row in ipairs(result) do
return tonumber(row['width']), tonumber(row['height']), row['cached']
end
end
---Store width and height of the specified `imagename` to the Imageinfo cargo table and return them.
---Width and height are computed via the `#imgw:` and `#imgh:` parser functions, respectively.
---@param imagename string
---@return number width
---@return number height
local function storeInfoToCargo(imagename)
-- don't cache {{item}}'s result when parsing imagesize fails.
should_cache = false
local imageTitle = mw.title.new("File:" .. imagename)
local width, height = imageTitle.file.width, imageTitle.file.height
if width and width ~= 0 and height and height ~= 0 then
should_cache = true -- ok, cache it.
currentFrame:callParserFunction('#cargo_store:_table=Imageinfo',{
image = imagename,
width = width,
height = height,
cached = os.time(),
})
end
return width, height
end
---Retrieve the dimensions of the specified `image` from the Imageinfo cargo table.
---If it doesn't have any data for the image yet, store it.
---@param imagename string
---@return number width
---@return number height
local function getSizeInfo(imagename)
local width, height, cached = getInfoFromCargo(imagename)
-- cache missed, init cache
if not cached then
width, height = storeInfoToCargo(imagename)
end
if width == 0 then width = nil end
if height == 0 then height = nil end
return width, height
end
---Compute the final width and height of the image.
---If necessary, retrieve data from or store data to the Imageinfo cargo table.
---@param imagename string
---@param width number
---@param height number
---@param scale number
---@param maxwidth number
---@param maxheight number
---@return number width
---@return number height
local function getImageSize(imagename, width, height, scale, maxwidth, maxheight)
-- get size info from image file itself (may be expensive)
local w, h = getSizeInfo(imagename) -- store data to cache
-- if width and height are not given as input, but scale/maxwidth/maxheight are, then
-- set width and height to the original dimensions of the image
if not width and not height and (scale or maxwidth or maxheight) then
width, height = w, h
end
-- apply scale to width/height if needed
if scale then
if width then width = width * scale end
if height then height = height * scale end
end
-- apply maxwidth/maxheight
if maxwidth then
if width then
if width > maxwidth then width = maxwidth end
else
if height then width = maxwidth end
end
end
if maxheight then
if height then
if height > maxheight then height = maxheight end
else
if width then height = maxheight end
end
end
-- round to natural numbers
if width then width = math.ceil(width) end
if height then height = math.ceil(height) end
return width, height
end
---Extract width and height from an input string.
---Example: `6x9px` → `6`, `9`
---@param maxsize string
---@return number maxwidth
---@return number maxheight
local function parseMaxSize(maxsize)
if not maxsize then return end
local maxwidth, maxheight = unpack(explode('x', string.gsub(maxsize, 'px', '')))
maxwidth, maxheight = tonumber(maxwidth), tonumber(maxheight)
if maxwidth == 0 then maxwidth = nil end
if maxheight == 0 then maxheight = nil end
return maxwidth, maxheight
end
---Assemble the final wikicode for an image.
---@param imagename string
---@param link string
---@param text string
---@param size string As accepted by the `[[File:` syntax, e.g. `5x7px*0.75`.
---@param scale number This will be multiplied by the scale in `size`, if necessary.
---@param maxsize string
---@return string
local function imagecode(imagename, link, text, size, scale, maxsize)
local image_output = '[[File:' .. imagename .. '|link='.. link .. '|' .. text
if size or scale or maxsize then
local basescale, width, height = parseSize(size) -- width, height: number or nil (basescale is string!)
scale = (tonumber(scale) or 1) * (tonumber(basescale) or 1) -- combine the scale parameter and scale from the size parameter
if scale == 0 or scale == 1 then
scale = nil
end
local maxwidth, maxheight = parseMaxSize(maxsize)
width, height = getImageSize(imagename, width, height, scale, maxwidth, maxheight) -- can be 0
if width or height then
image_output = image_output .. '|' .. (width or '') .. 'x' .. (height or '') .. 'px'
end
end
return image_output .. ']]'
end
---Return the full `[[File:` wikicode for each image in the input (multiple are separated with `/`).
---@param image string
---@param link string
---@param text string
---@param size string
---@param scale string
---@param maxsize string
---@return string
local function images(image, link, text, size, scale, maxsize)
if not image:find('/') then
-- there is only one image in the input
return imagecode(image, link, text, size, scale, maxsize)
end
-- there are multiple images in the input, separated with a slash
image = explode('/', image)
local result = ''
if size and size:find('/') then
-- there are multiple sizes in the size parameter
size = explode('/', size) -- so turn it into a table
for i, v in ipairs(image) do -- iterate over the images
result = result .. imagecode(v, link, text, size[i], scale, maxsize) -- create the wikicode (using the respective size)
end
else
for i, v in ipairs(image) do -- iterate over the images
result = result .. imagecode(v, link, text, size, scale, maxsize) -- create the wikicode
end
end
return result
end
---Return a string like `Internal Item ID: `, depending on the `_type`.
---@param _type '"item"'|'"tile"'|'"wall"'|'"npc"'|'"mount"'|'"buff"'|'"projectile"'|'"armor"'
---@return string
local function getIdText(_type)
local id_text
if _type == 'item' then -- a shortcut for faster
id_text = l10n('id_text_item')
elseif _type == 'tile' then
id_text = l10n('id_text_tile')
elseif _type == 'wall' then
id_text = l10n('id_text_wall')
elseif _type == 'npc' then
id_text = l10n('id_text_npc')
elseif _type == 'mount' then
id_text = l10n('id_text_mount')
elseif _type == 'buff' or _type == 'debuff' then
id_text = l10n('id_text_buff')
elseif _type == 'projectile' then
id_text = l10n('id_text_projectile')
elseif _type == 'armor' then
id_text = l10n('id_text_armor')
else
id_text = l10n('id_text_item')
end
return id_text
end
-----------------------------------------------------------------
-- main return object
return {
parse = parse,
go = function(frame, args)
-- cache?
if not args then
local cached = cache.get(':_item:' .. frame.args[1])
if cached then
return cached
end
end
-- init var cache
currentFrame = frame
args_table = args or parse(frame.args[1])
lang = getArg('lang') or 'en'
l10n_table = l10n_info[lang] or l10n_info['en']
local _arg1 = getArg(1) or ''
local _nolink = getArg('nolink')
local _link = _nolink and '' or getArg('link') or frame:expandTemplate{ title = 'tr', args = {_arg1, link='y', lang=lang} } -- now: _link == '' means nolink
local text = getArg(2) or ''
-- hovertext: {{tr|_arg1}} or text or _link (in that order)
local hovertext
if _arg1 ~= '' then
hovertext = frame:expandTemplate{ title = 'tr', args = {_arg1, lang=lang} }
elseif text ~= '' then
hovertext = text
else
hovertext = _link
end
-- set output flags
local output_image, output_text, output_table = true, true, false
local _mode = getArg('mode')
if _mode then
if _mode == 'image' or _mode == 'imageonly' or _mode =='onlyimage' then
output_text = false
elseif _mode == 'text' or _mode == 'noimage' then
output_image = false
elseif _mode == 'table' or _mode == '2-cell' then
output_table = true
end
end
local class = 'i'
local image_output, text_output
-- get wikicode for the image(s)
if output_image then
local image_arg = getArg('image')
if not image_arg then
if _arg1 == '1/2 Second Timer' then
image_arg = '1 2 Second Timer'
elseif _arg1 == '1/4 Second Timer' then
image_arg = '1 4 Second Timer'
else
image_arg = string.gsub(_arg1, ":%s*", " ")
end
image_arg = image_arg .. '.' .. (getArg('ext') or 'png')
end
if string.find(image_arg, '%[%[[fF]ile:') then
image_output = '<span class="img">' .. image_arg .. '</span>'
else
image_output = images(image_arg, _link, hovertext, getArg('size'), getArg('scale'), getArg('maxsize'))
end
else
image_output = ''
end
-- get wikicode for the text
if output_text then
local _note, _note2, _showid, _id, _icon = getArg('note'), getArg('note2'), getArg('showid'), getArg('id'), getArg('icons') -- get info from arguments
-- prepare: display ID?
if _id and not _showid then
_showid = true
end
if _showid and (_showid == 'n' or _showid == 'no') then
_showid = false
end
-- prepare: wrap?
local _wrap
if _showid or _note2 then
_wrap = false
else
_wrap = getArg('wrap')
end
-- prepare: link and display text
if _link ~= '' then
if text == _link then
text = '<span>[['..text..']]</span>'
else
text = '<span>[['.._link..'|'..text..']]</span>'
end
else
text = '<span title="'..hovertext..'">'..text..'</span>'
end
-- prepare: eicons
local icon = nil
if _icon == 'n' or _icon == 'no' or _icon == 'off' then
icon = ''
else
icon = eicons(getArg('epage') or _arg1, lang, (_showid or _note2 or _wrap or getArg('small')) and 'y')
end
-- assemble HTML code
local content = text -- item name link text first.
-- '-w' class means 'wrapmode', optimized for multiple lines of text. But it should be disabled for single line text.
if _wrap then
-- eicons in the same line
if icon ~= '' then
class = class .. ' -w'
content = content .. icon
end
-- note in a new line
if _note then
class = class .. ' -w'
content = content .. '<span class="note">' .. _note .. '</span>'
end
else
-- note in the same line
if _note then
content = content .. '<span class="note">' .. _note .. '</span>'
end
-- eicons in the same line
if icon ~= '' then
content = content .. icon
end
-- note2 in a new line
if _note2 then
class = class .. ' -w'
content = content .. '<div class="note">' .. _note2 .. '</div>'
end
-- id in a new line
if _showid then
class = class .. ' -w'
local idtype = (getArg('type') or 'item'):lower()
if not _id then
-- get ID automatically via {{itemIdFromName}} or the like
_id = frame:expandTemplate{ title = idtype .. 'IdFromName', args = {_arg1} }
end
local id_text = getIdText(idtype)
content = content .. '<div class="id">' .. id_text .. _id .. '</div>'
end
end
text_output = '<span>' .. content .. '</span>'
else
text_output = ''
end
-- handle custom CSS
local _class, _css = getArg('class'), getArg('css')
if _class then
class = class .. ' ' .. _class -- add to existing classes
end
local attr = {class = class}
if _css then
attr.style = _css -- set the style attribute to parameter value
end
local return_string
if output_table then
-- table output
attr.class = class
local _rowspan = getArg('rowspan')
local rowspan_text = (_rowspan and (' rowspan=' .. _rowspan) or '')
-- prepare the two cells
local first_cell_pre = rowspan_text .. ' class="il1c"'
local first_cell_content = mw.text.tag('span', attr, image_output)
local second_cell_pre = rowspan_text .. ' class="il2c"'
local second_cell_content = mw.text.tag('span', attr, text_output)
-- combine
return_string = first_cell_pre .. " | " .. first_cell_content .. " || " .. second_cell_pre .. " | " .. second_cell_content
else
-- non-table output (text/image)
return_string = mw.text.tag('span', attr, image_output .. text_output)
end
-- cache output for later reuse
if not args and should_cache then
cache.set(':_item:' .. frame.args[1], return_string, 3600*24) -- cache for 24 hours
end
-- output
return return_string
end,
purge = function(frame)
cache.delete(':_item:' .. frame.args[1]) -- delete that cache key.
end,
storeImageInfo = function(frame)
currentFrame = frame
local width, height = storeInfoToCargo(frame.args[1])
if not width or width == 0 or not height or height == 0 then
return
else
return frame:callParserFunction{name = "#dplvar:set", args = {
"_image_exist", "1",
"_image_width", width,
"_image_height", height,
}}
end
end,
}