Module:Inventory slot: Difference between revisions

From Modded Wiki
Jump to navigation Jump to search
Update to allow aliases to be pre-split, for better performance; also avoid splitting and stringifying input twice
No edit summary
Line 331: Line 331:
frame.mod = frameText:match( '([^:%]]+):' ) or mod
frame.mod = frameText:match( '([^:%]]+):' ) or mod
local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
if frame.mod == '' or vanilla[mw.ustring.lower( frame.mod )] then
if frame.mod and vanilla[mw.ustring.lower( frame.mod )] or frame.mod == '' then
frame.mod = nil
frame.mod = nil
end
end

Revision as of 06:02, 14 October 2016

This module implements {{inventory slot}}.

Dependencies

de:Modul:Slot es:Módulo:Inventory slot fr:Module:Case inventaire ja:モジュール:Inventory slot ko:모듈:Inventory slot pl:Moduł:Inventory slot ru:Модуль:Инвентарный слот pt:Módulo:Inventory slot uk:Модуль:Інвентарний слот zh:模块:Inventory slot



local p = {}

-- List of special prefixes which should be handled by
-- other modules (such as being moved outside links)
p.prefixes = {
	'Any',
	'Matching',
	'Damaged'
}

local function mergeList( parentTable, content )
	if content[1] then
		-- Merge list into table
		for _, v in ipairs( content ) do
			table.insert( parentTable, v )
		end
	else
		-- Add strings or tables to table
		table.insert( parentTable, content )
	end
end

local function cloneTable( origTable )
	local newTable = {}
	for k, v in pairs( origTable ) do
		if type( v ) == 'table' then
			v = cloneTable( v )
		end
		newTable[k] = v
	end
	return newTable
end

function p.slot( 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:Inventory slot/Aliases' )
	
	local modAliases = args.modaliases or ''
	if modAliases ~= '' then
		modAliases = mw.loadData( 'Module:' .. modAliases )
	else
		modAliases = nil
	end
	
	local randomise
	if args.class == 'invslot-large' then
		randomise = false
	end
	local frames = {}
	for frameText in mw.text.gsplit( args[1], '%s*;%s*' ) do
		local frame = p.makeFrame( frameText, args.mod )
		
		local id = frame.name
		if frame.mod then
			id = frame.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
			mergeList( frames, p.expandAlias( alias, frame ) )
		else
			table.insert( frames, frame )
		end
		-- Randomise starting frame for "Any *" aliases, as long as the alias is the only frame
		-- and this isn't an output slot
		if randomise ~= false and frame.name:match( '^Any ' ) then
			randomise = true
		else
			randomise = false
		end
	end
	
	local sprite
	local ids = mw.loadData( [[Module:InvSprite/IDs]] ).ids
	local modIds = {}
	local animated = #frames > 1
	local pageName = mw.title.getCurrentTitle().text
	local imgClass = args.imgclass
	local numStyle = args.numstyle
	local body = mw.html.create( 'span' ):addClass( 'invslot' ):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
		body:css( 'background-image', '{{FileUrl|' .. args.default .. '.png}}' )
	end
	
	local activeFrame = randomise and math.random( #frames ) or 1
	for i, frame in ipairs( frames ) do
		local item
		if frame ~= '' or frame.name == '' and animated then
			item = body:tag( 'span' ):addClass( 'invslot-item' )
			if imgClass then
				item:addClass( imgClass )
			end
		end
		
		if frame == '' or frame.name == '' then
			( item or body ):tag( 'br' )
		else
			local category
			local title = frame.title or mw.text.trim( args.title or '' )
			local mod = frame.mod
			local name = frame.name
			local num = frame.num
			local description = frame.text
			
			local img, idData
			if mod then
				local modData = modIds[mod]
				if not modData and mw.title.new( 'Module:InvSprite/Mods/' .. mod .. '/IDs' ).exists then
					modData = mw.loadData( 'Module:InvSprite/Mods/' .. mod .. '/IDs' )
					modIds[mod] = modData
				end
				if modData and modData[name] then
					idData = modData[name]
				else
					img = 'Grid ' .. name .. ' (' .. mod .. ').png'
				end
			elseif ids[name] then
				idData = ids[name]
			elseif name:match( '\.gif$' ) or name:match( '\.png$' ) then
				img = 'Invicon ' .. name
				name = name:sub( 0, -5 )
			else
				img = 'Grid ' .. name .. '.png'
			end
			
			local link = args.link or ''
			if link == '' then
				if mod then
					link = 'Mods/' .. mod .. '/' .. name
				else
					link = name:gsub( '^Damaged ', '' )
				end
			elseif link:lower() == 'none' then
				link = nil
			end
			if link == pageName then
				link = nil
			end
			
			local formattedTitle
			local plainTitle
			if title == '' then
				plainTitle = name
			elseif title:lower() ~= 'none' then
				plainTitle = title:gsub( '\\\\', '\' ):gsub( '\\&', '&' )
				
				local formatPattern = '&[0-9a-fk-or]'
				if plainTitle:match( formatPattern ) then
					formattedTitle = title
					plainTitle = plainTitle:gsub( formatPattern, '' )
				end
				
				if plainTitle == '' then
					plainTitle = name
				else
					plainTitle = plainTitle:gsub( '\', '\\' ):gsub( '&', '&' )
				end
			elseif link then
				if img then
					formattedTitle = ''
				else
					plainTitle = ''
				end
			end
			
			item:attr{
				['data-minetip-title'] = formattedTitle,
				['data-minetip-text'] = description
			}
			
			if img then
				-- & is re-escaped because mw.html treats attributes
				-- as plain text, but MediaWiki doesn't
				local escapedTitle = ( plainTitle or '' ):gsub( '&', '&' )
				item:addClass( 'invslot-item-image' )
					:wikitext( '[[File:', img, '|32x32px|link=', link or '', '|', escapedTitle, ']]' )
			else
				if not sprite then
					sprite = require( [[Module:Sprite]] ).sprite
				end
				local image
				if mod then
					image = args.spritesheet or mod .. 'Sprite.png'
				end
				if link then
					item:wikitext( '[[', link, '|' )
				end
				local image, spriteCat = sprite{
					iddata = idData, title = plainTitle,
					image = image, settings = 'InvSprite'
				}
				item:node( image )
				category = spriteCat
			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( 'invslot-stacksize' )
						:attr{ title = plainTitle }
						:wikitext( num )
				if numStyle then
					number:cssText( numStyle )
				end
				if img and link then
					item:wikitext( ']]' )
				end
			end
			
			if idData and link then
				item:wikitext( ']]' )
			end
			
			item:wikitext( category )
		end
		
		if i == activeFrame and animated and item then
			item:addClass( 'animated-active' )
		end
	end
	
	return tostring( body )
end

function p.getAlias( alias, parentFrame )
	local aliasFrames
	if type( alias ) == 'string' then
		aliasFrames = {}
		for frameText in mw.text.gsplit( alias, '%s*;%s*' ) do
			table.insert( aliasFrames, p.makeFrame( frameText ) )
		end
	else
		aliasFrames = alias
	end
	
	-- If alias is just a name, return the original frame with the new name
	if type( aliasFrames ) == 'string' then
		local aliasParts = mw.clone( parentFrame )
		aliasParts.name = aliasFrames
		return aliasParts
	end
	
	-- Single frame alias, put in list
	if aliasFrames.name then
		aliasFrames = { aliasFrames }
	end
	
	local expandedFrames = {}
	for i, aliasFrame in ipairs( aliasFrames ) do
		local aliasParts
		if type( aliasFrame ) == 'string' then
			aliasParts = { name = aliasFrame }
		else
			aliasParts = cloneTable( aliasFrame )
		end
		aliasParts.title = parentFrame.title or aliasParts.title
		aliasParts.mod = parentFrame.mod or aliasParts.mod
		aliasParts.num = parentFrame.num or aliasParts.num
		aliasParts.text = parentFrame.text or aliasParts.text
		
		expandedFrames[i] = aliasParts
	end
	
	return expandedFrames
end
function p.expandAlias( parentFrame, alias )
	return p.getAlias( alias, parentFrame )
end

function p.stringifyFrame( frame )
	if not frame.name then
		return ''
	end
	return string.format(
		'[%s]%s:%s,%s[%s]',
		frame.title or '',
		frame.mod or 'Minecraft',
		frame.name,
		frame.num or '',
		frame.text or ''
	)
end

function p.stringifyFrames( frames )
	for i, frame in ipairs( frames ) do
		frames[i] = p.stringifyFrame( frame )
	end
	return table.concat( frames, ';' )
end

function p.makeFrame( frameText, mod )
	-- Simple frame with no parts
	if not frameText:match( '[%[:,]' ) then
		return {
			mod = mod,
			name = mw.text.trim( frameText ),
		}
	end
	
	frameText = frameText:gsub( '%s*([%[%]:,;])%s*', '%1' )
	
	local frame = {}
	frame.title = frameText:match( '^%[([^%]]+)%]' )
	
	frame.mod = frameText:match( '([^:%]]+):' ) or mod
	local vanilla = { v = 1, vanilla = 1, mc = 1, minecraft = 1 }
	if frame.mod and vanilla[mw.ustring.lower( frame.mod )] or frame.mod == '' then
		frame.mod = nil
	end
	
	local nameStart = ( frameText:find( ':' ) or frameText:find( '%]' ) or 0 ) + 1
	if nameStart - 1 == #frameText then
		nameStart = 1
	end
	frame.name = frameText:sub( nameStart, ( frameText:find( '[,%[]', nameStart ) or 0 ) - 1 )
	
	frame.num = math.floor( frameText:match( ',(%d+)' ) or 0 )
	if frame.num == 0 then
		frame.num = nil
	end
	
	frame.text = frameText:match( '%[([^%]]+)%]$' )
	
	return frame
end
function p.getParts( frameText, mod )
	return p.makeFrame( frameText, mod )
end
 
return p