Module:Sprite: Difference between revisions

From Modded Wiki
Jump to navigation Jump to search
Improve speed by only lowercasing each name once
mw.html seems to use a lot of memory. Converting elements to wikitext string where possible before inserting them into an existing HtmlBuilder significantly reduces that memory usage for some reason, even though that just happens later anyway on output.
Line 104: Line 104:
end
end
return root
return tostring( root )
end
end


Line 221: Line 221:
local box = section.boxes:tag( 'li' ):addClass( 'spritedoc-box' ):attr( 'data-pos', pos )
local box = section.boxes:tag( 'li' ):addClass( 'spritedoc-box' ):attr( 'data-pos', pos )
box:tag( 'div' ):addClass( 'spritedoc-image' )
box:tag( 'div' ):addClass( 'spritedoc-image' )
:node( p.base{ pos = pos, settings = settingsPage } )
:wikitext( p.base{ pos = pos, settings = settingsPage } )
names = box:tag( 'ul' ):addClass( 'spritedoc-names' )
names = box:tag( 'ul' ):addClass( 'spritedoc-names' )
section[pos] = names
section[pos] = names
end
end
local codeElem = names
local nameElem = mw.html.create( 'li' ):addClass( 'spritedoc-name' )
:tag( 'li' ):addClass( 'spritedoc-name' )
local codeElem = nameElem:tag( 'code' ):wikitext( data.name )
:tag( 'code' ):wikitext( data.name )
if idData.deprecated then
if idData.deprecated then
codeElem:addClass( 'spritedoc-deprecated' )
codeElem:addClass( 'spritedoc-deprecated' )
end
end
names:wikitext( tostring( nameElem ) )
end
end
Line 238: Line 238:
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 06:17, 17 August 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' )
	
	if setting( 'stylesheet' ) then
		sprite:addClass(
			setting( 'classname' ) or
			mw.ustring.lower( setting( 'name' ):gsub( ' ', '-' ) ) .. '-sprite'
		)
	else
		sprite:css(
			'background-image',
			'{{FileUrl|' .. ( setting( 'image' ) or setting( 'name' ) .. 'Sprite.png' ) .. '}}'
		)
	end
	if setting( 'class' ) then
		sprite:addClass( setting( 'class' ) )
	end
	
	local size = setting( 'size' )
	local pos = math.abs( setting( 'pos' ) ) - 1
	local tiles = setting( 'sheetsize' ) / size
	local left = pos % tiles * size
	local top = math.floor( pos / tiles ) * size
	local scale = setting( 'scale' )
	if left > 0 or top > 0 then
		sprite:css( '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
	if size ~= defaultStyle.size or ( not setting( 'autoscale' ) and scale ~= defaultStyle.scale ) then
		sprite:css( 'height', size * scale .. 'px;width:' .. size * scale .. 'px' )
	end
	if setting( 'align' ) ~= defaultStyle.align then
		sprite:css( 'vertical-align', setting( 'align' ) )
	end
	if css then
		sprite:cssText( css )
	end
	
	local root
	local spriteText
	if setting( 'text' ) then
		root = mw.html.create( 'span' ):addClass( 'nowrap' )
		spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( setting( 'text' ) )
	end
	
	if setting( 'title' ) then
		( root or sprite ):attr( 'title', setting( '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' )
	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 not idData and allowCats then
			table.insert( categories, '[[Category:Pages with missing sprites]]' )
		else
			if idData.deprecated and allowCats then
				table.insert( categories, '[[Category:Pages using deprecated sprite names]]' )
			end
			
			args.pos = idData.pos
		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