Module:Factory slot
Jump to navigation
Jump to search
Documentation for this module may be created at Module:Factory slot/doc
-- Used to render Factory inventory slots
-- Inspired by and partially based on Minecraft Wiki's [[Module:Inventory slot]]
require("Module:No globals");
local checkType = require("libraryUtil").checkType;
local ustr = mw.ustring;
local INFINITY = "∞";
-- Workaround until this wiki gets TemplateStyles
local styles = {
[".factoryslot"] = [[
display: inline-block;
border: 1px solid black;
width: 32px;
height: 32px;
padding: 8px;
line-height: 1;
]],
[".factoryslot-item"] = [[
display: block;
position: relative;
width: 32px;
height: 32px;
margin: -4px;
padding: 4px;
]],
[".pixel-image"] = [[
image-rendering: crisp-edges;
image-rendering: pixelated;
]],
[".factoryslot-item .factoryslot-stacksize"] = [[
position: absolute;
bottom: 0;
right: 0;
white-space: nowrap;
font-family: sans-serif !important;
font-style: normal !important;
]],
};
local p = {};
--- Formats the item stack count
--- @param count integer
--- @return string|nil
function p.formatCount(count)
checkType('"Module:Factory slot".formatCount', 1, count, "number");
count = math.floor(count);
if (count >= 1e18) then
return INFINITY;
end
if (count < 2) then
return nil;
end
if (count < 1e6) then
-- less than a million
return tostring(count);
end
local exp = 3;
while true do
exp = exp + 3;
count = math.floor(count / 1e3 + 0.5);
if (count < 1e6 or exp == 15) then
--- @type string, string
local result, b = tostring(count):match("^(%d-%d)(%d%d%d)$");
b = b:gsub("0+$", "");
if (b ~= "") then
result = result .. "." .. b;
end
result = result .. "e" .. exp;
return result;
end
end
end
--- @class ItemStack
--- @field name string
--- @field count? number
--- Creates the actual HTML node for a given item stack
---
--- @param stack ItemStack
--- @param args? table
local function makeItem(stack, args)
args = args or {}
local item = mw.html.create("span")
:addClass("factoryslot-item")
:addClass(args.itemClass)
-- :cssText(styles[".factoryslot-item"])
:cssText(args.itemStyle);
local name = stack.name;
if ((name or "") == "") then
-- Empty stack
return nil;
end
local img = name .. ".png";
local link = args.link;
if ((link or "") == "") then
link = nil;
elseif (string.lower(link) == "no") then
link = nil;
end
local altText = img .. ": The Perfect Tower 2 Factory inventory icon of " .. name
if (link) then
altText = altText .. " linking to " .. link
end
item:addClass("pixel-image")
-- :cssText(styles[".pixel-image"])
:wikitext("[[File:", img, "|32x32px|link=", link or "", "|alt=", altText, "|", name, "]]");
local count = stack.count;
if (count and count > 1) then
count = p.formatCount(count);
if (count ~= nil) then
if (link) then
item:wikitext("[[", link, "|");
end
local number = item:tag("span")
:addClass("factoryslot-stacksize")
-- :cssText(styles[".factoryslot-item .factoryslot-stacksize"])
:attr("title", name)
:wikitext(count);
number:cssText(args.numStyle);
if (link) then
item:wikitext("]]");
end
end
end
return item;
end
p._makeItem = makeItem;
--- Parses an Item Stack Definition into an ItemStack table
---
--- Syntax:
--- ```text
--- <Name:string> ( ',' <Count:number> )?
--- ```
---
--- @param itemStackDesc string
--- @return ItemStack
function p.parseStack(itemStackDesc)
-- Simple stack definition with no parts or reserved characters
if (not string.match(itemStackDesc, "[:,]")) then
return { name = itemStackDesc };
end
local stack = {};
local name, count;
name, count = ustr.match(itemStackDesc, "^%s*(.*),%s*([" .. INFINITY .. "0-9%.e]+)%s*$");
if (count == INFINITY) then
count = math.huge;
else
count = count and tonumber(count);
end
if (count) then
stack.name = mw.text.trim(name);
if (count >= 1e18) then
count = math.huge;
else
count = math.floor(count);
end
stack.count = count;
else
stack.name = mw.text.trim(itemStackDesc);
end
return stack;
end
--- Stringifies an ItemStack table into an Item Stack Definition string
---
--- @param itemStack ItemStack
--- @return string
function p.stringifyStack(itemStack)
local name = itemStack.name;
local count = itemStack.count;
local result = name;
if (count and count >= 0) then
if (count >= 1e18) then
count = INFINITY;
else
count = tostring(count);
end
result = result .. "," .. count;
end
return result;
end
--- Main entry point.
--- Builds the HTML for a Factory inventory slot.
---
--- @param args any
function p.slot(args)
local stack = args[1];
if (type(stack) == "string") then
stack = p.parseStack(stack);
end
local body = mw.html.create("span")
:addClass("factoryslot")
:addClass(args.class)
-- :cssText(styles[".factoryslot"])
:cssText(args.style);
if (not stack) then
return body;
end
body:node(makeItem(stack, args));
return body;
end
-- Main template entry point.
function p.main(frame)
return p.slot(require("Module:Arguments").getArgs(frame, {
frameOnly = false,
wrappers = { "Template:Factory slot" },
}));
end
return p;