Module:Sprite

local util_args = require('Module:ArgsUtil') local util_table = require('Module:TableUtil') local util_text = require('Module:TextUtil') local lang = mw.getLanguage('en')

local h = {}

function h.castArgs(args) local ARGS_TO_CAST = { 'noimage', 'nolink', 'notext', 'dark', 'black', 'backwards' } for _, v in ipairs(ARGS_TO_CAST) do		args[v] = util_args.castAsBool(args[v]) end args.width = tonumber(args.width) args.height = tonumber(args.height) args.size = tonumber(args.size) end

function h.addDataToArgs(input, settings, ids) local displayKey = settings.lengthkey or settings.defaultlengthkey or 'link' local idKey = settings.linkkey or settings.defaultlinkkey or 'link' h.getIdAndKey(input, settings, idKey, displayKey) settings.link = (settings.link or settings.id) .. (settings.autolinksuffix or '') util_table.merge(settings, ids[settings.id]) end

function h.getIdAndKey(input, settings, idKey, displayKey) if not settings.lookup then settings.id = input:lower settings.display = input return end local lookup = mw.loadData('Module:' .. settings.lookup) local lookupResult = util_args.lookupVars(input, lookup) or {} settings.id = lookupResult[idKey] or input settings.display = settings.display or lookupResult[displayKey] or input end

function h.makeOutput(settings) if settings.noimage and settings.nolink then return settings.display elseif settings.noimage then return ('%s'):format(settings.id, settings.display) elseif settings.notext and settings.nolink then return h.sprite(settings) elseif settings.notext then local sprite = h.sprite(settings) return h.addLinkToSprite(sprite, settings) elseif settings.nolink then return tostring(h.makeSpriteAndText(settings)) else local sprite = h.makeSpriteAndText(settings) return h.addLinkToSprite(sprite, settings) end end

function h.makeSpriteAndText(settings) local sprite = h.sprite(settings) local spriteText = h.makeSpriteText(settings) local root = mw.html.create('span') :addClass('nowrap') if settings.backwards then root:node(spriteText) root:node(sprite) else root:node(sprite) root:node(spriteText) end return root end

function h.makeSpriteText(settings) local text = mw.html.create('span') if settings.backwards then text:addClass('sprite-text-backwards') else text:addClass('sprite-text') end text:wikitext(settings.display) return text end

function h.addLinkToSprite(sprite, settings) return util_text.printLink(settings.link, tostring(sprite)) end

function h.sprite(settings) local sprite = mw.html.create('span') sprite:tag('br') h.addClassesToSprite(sprite, settings) local styles = h.getStyles(settings) sprite:cssText(util_table.concat(styles,';')) return sprite end

function h.addClassesToSprite(sprite, settings) sprite:addClass(settings.class) :addClass('sprite') :addClass(h.getTypeClass(settings)) if settings.black then sprite:addClass('black-sprite') end if settings.dark then sprite:addClass('dark-sprite') end end

function h.getTypeClass(settings) if settings.classname then return settings.classname else local name = lang:lc(settings.name) return name .. '-sprite' end end

function h.getStyles(settings) local width = settings.size or settings.width local height = settings.size or settings.height local spacing = settings.spacing * (width / settings.defaultwidth) local sheetWidth = settings.sheetsize local tiles = (sheetWidth + settings.spacing) / (settings.defaultwidth + settings.spacing) local pos = math.abs(settings.pos or 1) - 1 local left = math.floor(pos % tiles * (width + spacing) + 0.5) local top = math.floor(math.floor(pos / tiles) * (height + spacing) + 0.5) local styles = { 'background-image:' .. settings.url, 'background-position:' .. h.getBackgroundPosition(left, top), 'background-size:' .. h.getBackgroundSize(width, spacing, tiles), util_args.nilToFalse(settings.css) }	if not settings.nosize then styles[#styles+1] = 'width:' .. width .. 'px' styles[#styles+1] = 'height:' .. height .. 'px' end return styles end

function h.getBackgroundPosition(left, top) return ('-%spx -%spx'):format(left, top) end

function h.getBackgroundSize(width, spacing, tiles) local width = math.floor((width + spacing) * tiles - spacing + 0.5) return width .. 'px auto' end

local p = {} function p.main(frame) local args = util_args.merge(true) h.castArgs(args) return p._main(args) end

function p.sprite(args) return p._main(args) end

function p.spriteImage(args) local sheet = mw.loadData(('Module:%sSprite'):format(args.type)) local settings = util_table.shallowClone(sheet.settings or {}) if args[1] == '' then args[1] = nil end local input = args[1] or settings.emptyimage settings.defaultwidth = settings.width util_table.merge(settings, args) util_table.merge(settings, sheet.ids[input:lower]) return tostring(h.sprite(settings)) end

function p._main(args) local sheet = mw.loadData(('Module:%sSprite'):format(args.type)) local settings = util_table.shallowClone(sheet.settings or {}) if args[1] == '' then args[1] = nil end local input = args[1] or settings.emptyimage if not input then return '' end input = input:lower if not (args["variant"] == nil) then input = args["variant"]:lower .. " " .. input end settings.defaultwidth = settings.width settings.link = args[1] util_table.merge(settings, args) h.addDataToArgs(input, settings, sheet.ids) local cat = (not settings.pos and args[1] and not settings.nocat) and  or  return tostring(h.makeOutput(settings)), cat end

function p.getUrl( spritesheet, query ) return mw.getCurrentFrame:expandTemplate{ title = 'FileUrl', args = { spritesheet, query = query } } end

function h.getDocBody(data, sprite_type, dataPage) local spritesheet = data.settings.image or data.settings.name .. 'Sprite.png' local f = mw.getCurrentFrame local body = mw.html.create('div'):attr({		id = 'spritedoc',		['data-dataprotection'] = 'edit',		['data-datatimestamp'] = f:callParserFunction( 'REVISIONTIMESTAMP', 'Module:' .. dataPage ),		['data-datapage'] = 'Module:' .. dataPage,		['data-spritesheet'] = spritesheet,		['data-spriteprotection'] = 'edit,upload,reupload',		['data-urlfunc'] = "require( Module:Sprite ).getUrl( '" .. spritesheet .. "', '$1' )",		['data-refreshtext'] = mw.text.nowiki( '' ),		['data-settings'] = mw.text.jsonEncode( data.settings ),	}) return body end

function p.doc(frame) local DROPDOWN_TOGGLE_OPTIONS = { 'deprecated', 'nolink', 'black', 'dark' } local args = util_args.merge(true) local sprite_type = args[1] local dataPage = sprite_type .. 'Sprite' local data = mw.loadData('Module:' .. dataPage) local body = h.getDocBody(data, sprite_type, dataPage) local sections = {} for _, sectionData in ipairs( data.sections or { name = 'Uncategorized' } ) do		local sectionTag = body:tag( 'div' ):addClass( 'spritedoc-section' ):attr( 'data-section-id', sectionData.id ) sectionTag:tag( 'h3' ):wikitext( sectionData.name ) sections[sectionData.id] = { boxes = sectionTag:tag( 'ul' ):addClass( 'spritedoc-boxes' ) } end local keyedData = {} local i = 1 for name, idData in pairs( data.ids ) do		keyedData[i] = { sortKey = lang:lc( name ), name = name, data = idData, }		i = i + 1 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._main({ data.name, type = sprite_type, notext = true, nolink = true }) ) 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 ) for _, v in ipairs(DROPDOWN_TOGGLE_OPTIONS) do			if idData[v] then codeElem:addClass('spritedoc-' .. v)			end end names:wikitext( tostring( nameElem ) ) end return body end return p