Module:Grid

*Documentation for this module may be created at Module:Grid/doc*

```
local defaultMod = 'IDTMod'
local p = {}

-- Individual cell
function p.cell( f )
 local args = f.args or f
 if f == mw.getCurrentFrame() and args[1] == nil then
 args = f:getParent().args
 end

 args[1] = mw.text.trim( args[1] or '' )

 -- Comment this next line out if you're not using aliases
 --local aliases = mw.loadData( 'Module:Grid/Aliases' )

 local modAliases = args.modaliases or ''
 if modAliases ~= '' then
 modAliases = mw.loadData( 'Module:' .. modAliases )
 else
 modAliases = nil
 end

 if aliases or modAliases then
 local frames = {}
 for frame in mw.text.gsplit( args[1], '%s\*;%s\*' ) do
 local frameParts = p.getParts( frame, args.mod )

 local id = frameParts.name
 if frameParts.mod then
 id = frameParts.mod .. ':' .. id
 end

 local alias
 if modAliases and modAliases[id] then
 alias = modAliases[id]
 elseif aliases and aliases[id] then
 alias = aliases[id]
 end

 if alias then
 table.insert( frames, p.expandAlias( frameParts, alias ) )
 else
 table.insert( frames, frame )
 end
 end

 args[1] = table.concat( frames, ';' )
 end

 local sprite
 --local ids = mw.loadData( [[Module:Grid/IDs]] )
 local modIds = {}
 local animated = args[1]:find( ';' )
 local pageName = mw.title.getCurrentTitle().subpageText
 local imgClass = args.imgclass
 local numStyle = args.numstyle
 local body = mw.html.create( 'span' ):addClass( 'grid' ):css{ ['vertical-align'] = args.align }
 if animated then
 body:addClass( 'animated' )
 end
 if args.class then
 body:addClass( args.class )
 end
 if args.style then
 body:cssText( args.style )
 end

 if ( args.default or '' ) ~= '' then
 local item = body
 :tag( 'span' )
 :addClass( 'grid-default-item' )
 :wikitext( '[[File:Grid ', args.default, '.png|32x32px|link=|alt=]]' )
 if animated then
 item:addClass( 'skip' )
 end
 end

 local first = true
 for frame in mw.text.gsplit( args[1], '%s\*;%s\*' ) do
 local item
 if frame ~= '' or frame == '' and animated then
 item = body:tag( 'span' ):addClass( 'grid-item' )
 if imgClass then
 item:addClass( imgClass )
 end
 end

 if frame == '' then
 ( item or body ):tag( 'br' )
 else
 local parts = p.getParts( frame, args.mod )
 local tooltipTitle = parts.title
 local mod = parts.mod
 local name = parts.name
 local num = parts.num
 local tooltipDesc = parts.text

 local img, spriteImg
 if mod then
 if not modIds[mod] and mw.title.new( 'Module:Grid/Mods/' .. mod .. '/IDs' ).exists then
 modIds[mod] = mw.loadData( 'Module:Grid/Mods/' .. mod .. '/IDs' )
 end
 if modIds[mod] and modIds[mod][name] then
 spriteImg = modIds[mod][name]
 else
 img = name .. ' (' .. mod .. ')'
 end
 elseif ids and ids[name] then
 spriteImg = ids[name]
 else
 img = name
 end

 local link = args.link or ''
 if link == '' then
 if name == pageName then
 link = 'none'
 elseif mod then
 link = 'mcw:'
 if mod ~= 'Minecraft' then
 link = link .. 'Mods/' .. mod .. '/'
 end
 link = link .. name
 else
 link = name
 end
 end

 local title = args.title or ''
 if title == '' then
 if tooltipTitle then
 title = tooltipTitle:gsub( '&[0-9a-fk-or]', '' )
 end
 if mw.text.trim( title ) == '' and ( link:lower() == 'none' or link ~= name ) then
 title = name
 end
 end

 if link:lower() == 'none' then
 link = nil
 end
 if title == '' then
 title = nil
 elseif title:lower() == 'none' then
 if link then
 title = ''
 else
 title = nil
 end
 end

 if img and ( title == '' or not link ) then
 item:attr{ title = title }
 end
 item:attr{
 ['data-minetip-title'] = tooltipTitle,
 ['data-minetip-text'] = tooltipDesc
 }

 if img then
 item:addClass( 'grid-item-image' )
 :wikitext( '[[File:Grid ', img, '.png|32x32px|link=', link or '', '|', title or '', ']]' )
 else
 if not sprite then
 sprite = require( [[Module:Sprite]] ).base
 end
 local settings = 'Grid/Settings'
 local image
 if mod == 'Minecraft' then
 settings = 'Grid/Mods/Minecraft/Settings'
 elseif mod then
 image = args.spritesheet or mod .. 'Sprite.png'
 end
 if link then
 item:wikitext( '[[', link, '|' )
 end
 item:wikitext( sprite{
 pos = spriteImg, title = title,
 image = image, settings = settings
 } )
 end

 if num and num > 1 and num < 1000 then
 if img and link then
 item:wikitext( '[[', link, '|' )
 end
 local number = item
 :tag( 'span' )
 :addClass( 'grid-number' )
 :attr{ title = title }
 :wikitext( num )
 if numStyle then
 number:cssText( numStyle )
 end
 if img and link then
 item:wikitext( ']]' )
 end
 end

 if spriteImg and link then
 item:wikitext( ']]' )
 end
 end

 if first then
 if animated and item then
 item:addClass( 'active' )
 end
 first = false
 end
 end

 return tostring( body )
end

function p.expandAlias( frameParts, alias )
 -- If the frame has no parts, we can just return the alias as-is
 if not frameParts.title and not frameParts.mod and not frameParts.num and not frameParts.text then
 return alias
 end

 local expandedFrames = {}
 for aliasFrame in mw.text.gsplit( alias, '%s\*;%s\*' ) do
 local aliasParts = p.getParts( aliasFrame )
 aliasParts.title = frameParts.title or aliasParts.title or ''
 aliasParts.mod = frameParts.mod or aliasParts.mod or defaultMod
 aliasParts.num = frameParts.num or aliasParts.num or ''
 aliasParts.text = frameParts.text or aliasParts.text or ''

 table.insert( expandedFrames, string.format(
 '[%s]%s:%s,%s[%s]',
 aliasParts.title, aliasParts.mod, aliasParts.name, aliasParts.num, aliasParts.text
 ) )
 end

 return table.concat( expandedFrames, ';' )
end

function p.getParts( frame, mod )
 local parts = {}
 parts.title = frame:match( '^%[%s\*([^%]]+)%s\*%]' )

 parts.mod = mw.text.trim( frame:match( '([^:%]]+):' ) or mod or '' )

 if parts.mod == '' or mw.ustring.lower( parts.mod ) == mw.ustring.lower( defaultMod ) then
 parts.mod = nil
 else
 local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
 if vanilla[mw.ustring.lower( parts.mod )] then
 parts.mod = 'Minecraft'
 end
 end

 local nameStart = ( frame:find( ':' ) or frame:find( '%]' ) or 0 ) + 1
 if nameStart - 1 == #frame then
 nameStart = 1
 end
 parts.name = mw.text.trim( frame:sub( nameStart, ( frame:find( '[,%[]', nameStart ) or 0 ) - 1 ) )

 parts.num = math.floor( frame:match( ',%s\*(%d+)' ) or 0 )
 if parts.num == 0 then
 parts.num = nil
 end

 parts.text = frame:match( '%[%s\*([^%]]+)%s\*%]$' )

 return parts
end

local addCell = function( args, item, prefix, class, default )
 prefix = prefix or item
 return p.cell{
 args[item], mod = args.Mod, link = args[prefix .. 'link'],
 title = args[prefix .. 'title'], class = class, default = default
 }
end

--- GUI variants; called directly to avoid the overhead of a bunch of #invoke calls per GUI
-- Crafting table
function p.craftingTable( f )
 local args = f
 if f == mw.getCurrentFrame() then
 args = f:getParent().args
 else
 f = mw.getCurrentFrame()
 end

 local body = mw.html.create( 'span' ):addClass( 'grid-Crafting\_Table' )

 local input = body:tag( 'span' ):addClass( 'grid-input' )
 for num = 1, 3 do
 local row = input:tag( 'span' ):addClass( 'grid-row' )
 for \_, letter in ipairs{ 'A', 'B', 'C' } do
 row:wikitext( addCell( args, letter .. num ) )
 end
 end

 local arrow = body:tag( 'span' ):addClass( 'grid-arrow' ):tag( 'br' ):done()
 if args.arrow or '' ~= '' then
 arrow:css( 'background-image',
 f:callParserFunction( '#widget:FileUrl', { url = args.arrow .. ' (' .. args.Mod .. ').png' } )
 )
 end

 body
 :tag( 'span' )
 :addClass( 'grid-output' )
 :wikitext( addCell( args, 'Output', 'O', 'grid-large' ) )

 if args.shapeless or '' ~= '' then
 body
 :tag( 'span' )
 :addClass( 'grid-icons' )
 :tag( 'span' )
 :addClass( 'grid-shapeless' )
 :attr( 'title',
 'This recipe is shapeless; the inputs may be placed in any arrangement in the crafting grid.'
 )
 :tag( 'br' )
 end

 return tostring( mw.html.create( 'div' ):node( body ) )
end

-- Furnace
function p.furnace( f )
 local args = f
 if f == mw.getCurrentFrame() then
 args = f:getParent().args
 else
 f = mw.getCurrentFrame()
 end

 local body = mw.html.create( 'span' ):addClass( 'grid-Furnace' )

 local input = body:tag( 'span' ):addClass( 'grid-input' )
 input:wikitext( addCell( args, 'Input', 'I' ) )
 local fuel = input:tag( 'span' ):addClass( 'grid-fuel' ):tag( 'br' ):done()
 local fuelImg = args.FuelUsage or ''
 local burning = args.Input or '' ~= '' and args.Fuel or '' ~= ''
 if not burning then
 fuel:addClass( 'grid-inactive' )
 if fuelImg ~= '' then
 fuelImg = fuelImg .. ' (in-active)'
 end
 end
 if fuelImg ~= '' then
 fuel:css( 'background-image', f:callParserFunction( '#widget:FileUrl', {
 url = 'Grid layout ' .. fuelImg .. ' (' .. args.Mod .. ').png'
 } ) )
 end
 input:wikitext( addCell( args, 'Fuel', 'F' ) )

 local arrow = body:tag( 'span' ):addClass( 'grid-arrow' ):tag( 'br' ):done()
 local arrowImg = args.Progress or ''
 if not burning or ( args.Output or '' ) == '' then
 arrow:addClass( 'grid-inactive' )
 if arrowImg ~= '' then
 arrowImg = arrowImg .. ' (in-active)'
 end
 end
 if arrowImg ~= '' then
 arrow:css( 'background-image', f:callParserFunction( '#widget:FileUrl', {
 url = 'Grid layout ' .. arrowImg .. ' (' .. args.Mod .. ').png'
 } ) )
 end

 body
 :tag( 'span' )
 :addClass( 'grid-output' )
 :wikitext( addCell( args, 'Output', 'O', 'grid-large' ) )

 return tostring( mw.html.create( 'div' ):node( body ) )
end

-- Brewing Stand
function p.brewingStand( f )
 local args = f
 if f == mw.getCurrentFrame() then
 args = f:getParent().args
 else
 f = mw.getCurrentFrame()
 end

 local body = mw.html.create( 'span' ):addClass( 'grid-Brewing\_Stand' )

 local input = body:tag( 'span' ):addClass( 'grid-input' )
 input:tag( 'span' ):addClass( 'grid-bubbling' ):tag( 'br' )
 input:wikitext( addCell( 'Input', 'I' ) )
 input:tag( 'span' ):addClass( 'grid-arrow' ):tag( 'br' )
 if args.Input or '' == '' or
 ( args.Output1 or '' ~= '' and args.Output2 or '' ~= '' and args.Output3 or '' ~= '' )
 then
 input:addClass( 'grid-inactive' )
 end

 body:tag( 'span' ):addClass( 'grid-paths' ):tag( 'br' )

 local output = body:tag( 'span' ):addClass( 'grid-output' )
 for i = 1, 3 do
 output:wikitext( addCell( args, 'Output' .. i, 'O' .. i, 'grid-output' .. i, 'layout Brewing Empty' ) )
 end

 return tostring( mw.html.create( 'div' ):node( body ) )
end

return p

```