Module:Sprite: Difference between revisions

From Modded Wiki
Jump to navigation Jump to search
Ignore empty links
Fix mw.html performance issue (basically doubles performance). Fix the css parameter not actually working.
Line 35: Line 35:
local sprite = mw.html.create( 'span' ):addClass( 'sprite' )
local sprite = mw.html.create( 'span' ):addClass( 'sprite' )
sprite:tag( 'br' )
sprite:tag( 'br' )
-- mw.html's css method performs very slow escaping, which doubles the time it takes
-- to run, so we'll construct the styles manually, and put them in the cssText
-- method, which only does html escaping (which isn't slow)
local styles = {}
if setting( 'stylesheet' ) then
if setting( 'stylesheet' ) then
Line 42: Line 47:
)
)
else
else
sprite:css(
table.insert( styles, 'background-image:{{FileUrl|' .. (
'background-image',
setting( 'image' ) or setting( 'name' ) .. 'Sprite.png'
'{{FileUrl|' .. ( setting( 'image' ) or setting( 'name' ) .. 'Sprite.png' ) .. '}}'
) .. '}}' )
)
end
end
if setting( 'class' ) then
local class = setting( 'class' )
sprite:addClass( setting( 'class' ) )
if class then
sprite:addClass( class )
end
end
local size = setting( 'size' )
local size = setting( 'size' )
local pos = math.abs( setting( 'pos' ) ) - 1
local pos = math.abs( setting( 'pos' ) ) - 1
local tiles = setting( 'sheetsize' ) / size
local sheetWidth = setting( 'sheetsize' )
local tiles = sheetWidth / size
local left = pos % tiles * size
local left = pos % tiles * size
local top = math.floor( pos / tiles ) * size
local top = math.floor( pos / tiles ) * size
local scale = setting( 'scale' )
local scale = setting( 'scale' )
local autoScale = setting( 'autoscale' )
if left > 0 or top > 0 then
if left > 0 or top > 0 then
sprite:css( 'background-position', '-' .. left * scale .. 'px -' .. top * scale .. 'px' )
table.insert( styles, 'background-position:-' .. left * scale .. 'px -' .. top * scale .. 'px' )
end
if not setting( 'autoscale' ) and scale ~= defaultStyle.scale then
sprite:css( 'background-size', setting( 'sheetsize' ) * scale .. 'px auto' )
end
end
if size ~= defaultStyle.size or ( not setting( 'autoscale' ) and scale ~= defaultStyle.scale ) then
if not autoScale and scale ~= defaultStyle.scale then
sprite:css( 'height', size * scale .. 'px;width:' .. size * scale .. 'px' )
table.insert( styles, 'background-size:' .. sheetWidth * scale .. 'px auto' )
end
end
if setting( 'align' ) ~= defaultStyle.align then
if size ~= defaultStyle.size or ( not autoScale and scale ~= defaultStyle.scale ) then
sprite:css( 'vertical-align', setting( 'align' ) )
table.insert( styles, 'height:' .. size * scale .. 'px' )
table.insert( styles, 'width:' .. size * scale .. 'px' )
end
end
if css then
local align = setting( 'align' )
sprite:cssText( css )
if align ~= defaultStyle.align then
table.insert( styles, 'vertical-align:' .. align )
end
end
table.insert( styles, setting( 'css' ) )
sprite:cssText( table.concat( styles, ';' ) )
local text = setting( 'text' )
local root
local root
local spriteText
local spriteText
if setting( 'text' ) then
if text then
root = mw.html.create( 'span' ):addClass( 'nowrap' )
root = mw.html.create( 'span' ):addClass( 'nowrap' )
spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( setting( 'text' ) )
spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( text )
end
end
if setting( 'title' ) then
local title = setting( 'title' )
( root or sprite ):attr( 'title', setting( 'title' ) )
if title then
( root or sprite ):attr( 'title', title )
end
end
Line 236: Line 247:
if args.refresh then
if args.refresh then
return tostring( body )
return '', tostring( body )
end
end
return f:callParserFunction( '#widget:Stylesheet', { page = 'SpriteDoc' } ), tostring( body )
return f:callParserFunction( '#widget:Stylesheet', { page = 'SpriteDoc' } ), tostring( body )
end
end
return p
return p

Revision as of 11:38, 8 September 2015

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

local p = {}
function p.base( f )
	local args = f
	if f == mw.getCurrentFrame() then 
		args = require( 'Module:ProcessArgs' ).merge( true )
	else
		f = mw.getCurrentFrame()
	end
	
	-- Default settings
	local default = {
		scale = 1,
		sheetsize = 256,
		size = 16,
		pos = 1,
		align = 'text-top'
	}
	
	local defaultStyle = default
	if args.settings then
		local settings = mw.loadData( 'Module:' .. args.settings )
		if not settings.stylesheet then
			-- Make a separate clone of the current default settings
			defaultStyle = mw.clone( default )
		end
		for k, v in pairs( settings ) do
			default[k] = v
		end
	end
	
	local setting = function( arg )
		return args[arg] or default[arg]
	end
	
	local sprite = mw.html.create( 'span' ):addClass( 'sprite' )
	sprite:tag( 'br' )
	
	-- mw.html's css method performs very slow escaping, which doubles the time it takes
	-- to run, so we'll construct the styles manually, and put them in the cssText
	-- method, which only does html escaping (which isn't slow)
	local styles = {}
	
	if setting( 'stylesheet' ) then
		sprite:addClass(
			setting( 'classname' ) or
			mw.ustring.lower( setting( 'name' ):gsub( ' ', '-' ) ) .. '-sprite'
		)
	else
		table.insert( styles, 'background-image:{{FileUrl|' .. (
			setting( 'image' ) or setting( 'name' ) .. 'Sprite.png'
		) .. '}}' )
	end
	local class = setting( 'class' )
	if class then
		sprite:addClass( class )
	end
	
	local size = setting( 'size' )
	local pos = math.abs( setting( 'pos' ) ) - 1
	local sheetWidth = setting( 'sheetsize' )
	local tiles = sheetWidth / size
	local left = pos % tiles * size
	local top = math.floor( pos / tiles ) * size
	local scale = setting( 'scale' )
	local autoScale = setting( 'autoscale' )
	
	if left > 0 or top > 0 then
		table.insert( styles, 'background-position:-' .. left * scale .. 'px -' .. top * scale .. 'px' )
	end
	if not autoScale and scale ~= defaultStyle.scale then
		table.insert( styles, 'background-size:' .. sheetWidth * scale .. 'px auto' )
	end
	if size ~= defaultStyle.size or ( not autoScale and scale ~= defaultStyle.scale ) then
		table.insert( styles, 'height:' .. size * scale .. 'px' )
		table.insert( styles, 'width:' .. size * scale .. 'px' )
	end
	local align = setting( 'align' )
	if align ~= defaultStyle.align then
		table.insert( styles, 'vertical-align:' .. align )
	end
	table.insert( styles, setting( 'css' ) )
	sprite:cssText( table.concat( styles, ';' ) )
	
	local text = setting( 'text' )
	local root
	local spriteText
	if text then
		root = mw.html.create( 'span' ):addClass( 'nowrap' )
		spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( text )
	end
	
	local title = setting( 'title' )
	if title then
		( root or sprite ):attr( 'title', title )
	end
	
	if not root then
		root = mw.html.create( '' )
	end
	root:node( sprite )
	if spriteText then
		root:node( spriteText )
	end
	
	local link = setting( 'link' ) or ''
	if link ~= '' and mw.ustring.lower( link ) ~= 'none' then
		-- External link
		if link:find( '//' ) then
			return '[' .. link .. ' ' .. tostring( root ) .. ']'
		end
		
		-- Internal link
		local linkPrefix = setting( 'linkprefix' ) or ''
		return '[[' .. linkPrefix .. link .. '|' .. tostring( root ) .. ']]'
	end
	
	return tostring( root )
end

function p.sprite( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	
	local categories = {}
	if tonumber( args[1] ) then
		args.pos = args[1]
		table.insert( categories, '[[Category:Pages using sprite positions]]' )
	else
		local idData = args.iddata
		if not idData then
			local default = {}
			if args.settings then
				default = mw.loadData( 'Module:' .. args.settings )
			end
			
			local name = args.name or default.name
			local ids = mw.loadData( 'Module:' .. ( args.ids or default.ids or name .. '/IDs' ) ).ids
			local id = mw.text.trim( args[1] or '' )
			idData = ids[id] or ids[mw.ustring.lower( id ):gsub( '[%s%+]', '-' )]
		end
		
		local allowCats = not mw.title.getCurrentTitle().isSubpage
		if idData then
			if idData.deprecated and allowCats then
				table.insert( categories, '[[Category:Pages using deprecated sprite names]]' )
			end
			
			args.pos = idData.pos
		elseif allowCats then
			table.insert( categories, '[[Category:Pages with missing sprites]]' )
		end
	end
	
	return p.base( args ), table.concat( categories, '' )
end

function p.link( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Module:ProcessArgs' ).merge( true )
	end
	
	local link = args[1]
	if args[1] and not args.id then
		link = args[1]:match( '^(.-)%+' ) or args[1]
	end
	local text = args.text or args[2] or link
	
	args[1] = args.id or args[1]
	args.link = args.link or link
	args.text = text
	
	return p.sprite( args )
end

function p.doc( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = f.args
	else
		f = mw.getCurrentFrame()
	end
	local settingsPage = mw.text.trim( args[1] )
	local settings = mw.loadData( 'Module:' .. settingsPage )
	local idsPage = 'Module:' .. ( settings.ids or settings.name .. '/IDs' )
	
	local body
	if args.refresh then
		body = mw.html.create()
	else
		local spriteSheet = settings.image or settings.name .. 'Sprite.png'
		body = mw.html.create( 'div' ):attr( {
			id = 'spritedoc',
			['data-idspage'] = '{{PAGEID:' .. idsPage .. '}}',
			['data-idstimestamp'] = '{{REVISIONTIMESTAMP:' .. idsPage .. '}}',
			['data-spritesheet'] = spriteSheet,
			['data-pos'] = settings.pos or 1,
			['data-refreshtext'] = mw.text.nowiki( '{{#invoke:sprite2|doc|' .. settingsPage .. '|refresh=1}}' )
		} )
	end
	
	local data = mw.loadData( idsPage )
	
	local sections = {}
	for _, sectionData in ipairs( data.sections or { 'Uncategorized' } ) do
		local sectionTag = body:tag( 'div' ):addClass( 'spritedoc-section' ):attr( 'data-section-id', sectionData.id )
		-- https://phabricator.wikimedia.org/T73594
		sectionTag:wikitext( '<h3>', sectionData[1], '</h3>' )
		sections[sectionData.id] = { boxes = sectionTag:tag( 'ul' ):addClass( 'spritedoc-boxes' ) }
	end
	
	local keyedData = {}
	for name, idData in pairs( data.ids ) do
		table.insert( keyedData, {
			sortKey = mw.ustring.lower( name ),
			name = name,
			data = idData
		} )
	end
	table.sort( keyedData, function( a, b )
		return a.sortKey < b.sortKey
	end )
	
	for _, data in ipairs( keyedData ) do
		local idData = data.data
		local pos = idData.pos
		local section = sections[idData.section]
		local names = section[pos]
		if not names then
			local box = section.boxes:tag( 'li' ):addClass( 'spritedoc-box' ):attr( 'data-pos', pos )
			box:tag( 'div' ):addClass( 'spritedoc-image' )
				:wikitext( p.base{ pos = pos, settings = settingsPage } )
			
			names = box:tag( 'ul' ):addClass( 'spritedoc-names' )
			section[pos] = names
		end
		local nameElem = mw.html.create( 'li' ):addClass( 'spritedoc-name' )
		local codeElem = nameElem:tag( 'code' ):wikitext( data.name )
		
		if idData.deprecated then
			codeElem:addClass( 'spritedoc-deprecated' )
		end
		names:wikitext( tostring( nameElem ) )
	end
	
	if args.refresh then
		return '', tostring( body )
	end
	return f:callParserFunction( '#widget:Stylesheet', { page = 'SpriteDoc' } ), tostring( body )
end
return p