Module:Sprite: Difference between revisions
m (1 revision) |
CraftSpider (talk | contribs) (Updated Module) |
||
Line 4: | Line 4: | ||
if f == mw.getCurrentFrame() then | if f == mw.getCurrentFrame() then | ||
args = require( 'Module:ProcessArgs' ).merge( true ) | args = require( 'Module:ProcessArgs' ).merge( true ) | ||
else | |||
f = mw.getCurrentFrame() | |||
end | end | ||
Line 12: | Line 14: | ||
size = 16, | size = 16, | ||
pos = 1, | pos = 1, | ||
align = 'text-top' | |||
align = 'text-top | |||
} | } | ||
local defaultStyle = | local defaultStyle = default | ||
if args.settings then | if args.settings then | ||
local settings = mw.loadData( 'Module:' .. args.settings ) | 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 | for k, v in pairs( settings ) do | ||
default[k] = v | default[k] = v | ||
end | end | ||
end | end | ||
local | local setting = function( arg ) | ||
local | return args[arg] or default[arg] | ||
end | |||
local | |||
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 | |||
local class = | -- 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 | local styles = {} | ||
local | |||
local | 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 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 autoScale = setting( 'autoscale' ) | |||
if left > 0 or top > 0 then | if left > 0 or top > 0 then | ||
table.insert( styles, 'background-position:-' .. left * scale .. 'px -' .. top * scale .. 'px' ) | table.insert( styles, 'background-position:-' .. left * scale .. 'px -' .. top * scale .. 'px' ) | ||
Line 61: | Line 72: | ||
end | end | ||
if size ~= defaultStyle.size or ( not autoScale and scale ~= defaultStyle.scale ) then | if size ~= defaultStyle.size or ( not autoScale and scale ~= defaultStyle.scale ) then | ||
table.insert( styles, 'height:' .. size * scale .. 'px | table.insert( styles, 'height:' .. size * scale .. 'px' ) | ||
table.insert( styles, 'width:' .. size * scale .. 'px' ) | |||
end | end | ||
local align = setting( 'align' ) | |||
if align ~= defaultStyle.align then | if align ~= defaultStyle.align then | ||
table.insert( styles, 'vertical-align:' .. align ) | 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 spriteText | |||
if text then | |||
root = mw.html.create( 'span' ):addClass( 'nowrap' ) | |||
spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( text ) | |||
end | end | ||
local title = setting( 'title' ) | |||
if title then | |||
( root or sprite ):attr( 'title', title ) | |||
end | end | ||
if not root then | |||
root = mw.html.create( '' ) | |||
end | |||
root:node( sprite ) | |||
if spriteText then | |||
root:node( spriteText ) | |||
if | |||
end | end | ||
if link ~= '' then | local link = setting( 'link' ) or '' | ||
if link ~= '' and mw.ustring.lower( link ) ~= 'none' then | |||
-- External link | |||
if link:find( '//' ) then | if link:find( '//' ) then | ||
return '[' .. link .. ' ' .. tostring( root ) .. ']' | |||
return ' | |||
end | end | ||
return | -- Internal link | ||
local linkPrefix = setting( 'linkprefix' ) or '' | |||
return '[[' .. linkPrefix .. link .. '|' .. tostring( root ) .. ']]' | |||
end | end | ||
return tostring( root ) | |||
end | end | ||
Line 103: | Line 122: | ||
if f == mw.getCurrentFrame() then | if f == mw.getCurrentFrame() then | ||
args = require( 'Module:ProcessArgs' ).merge( true ) | args = require( 'Module:ProcessArgs' ).merge( true ) | ||
else | |||
f = mw.getCurrentFrame() | |||
end | end | ||
local | local categories = {} | ||
local idData = args.iddata | |||
if not idData then | |||
local default = {} | local default = {} | ||
if args.settings then | if args.settings then | ||
Line 115: | Line 135: | ||
local name = args.name or default.name | local name = args.name or default.name | ||
local ids = mw.loadData( 'Module:' .. ( args.ids or default.ids or ' | local ids = mw.loadData( 'Module:' .. ( args.ids or default.ids or name .. '/IDs' ) ) | ||
local id = mw.text.trim( args[1] or '' ) | ids = ids.ids or ids | ||
local id = mw.text.trim( tostring( args[1] or '' ) ) | |||
if not | idData = ids[id] or ids[mw.ustring.lower( id ):gsub( '[%s%+]', '-' )] | ||
end | |||
local title = mw.title.getCurrentTitle() | |||
-- Remove categories on language pages, talk pages, and in User/UserWiki/UserProfile namespaces | |||
local disallowCats = args.nocat or title.isTalkPage or title.nsText:find( '^User' ) | |||
if idData then | |||
if type( idData ) == 'table' then | |||
if idData.deprecated and not disallowCats then | |||
table.insert( categories, f:expandTemplate{ title = 'Translation category', args = { 'Pages using deprecated sprite names', project = 0 } } ) | |||
end | |||
args.pos = idData.pos | |||
else | |||
args.pos = idData | |||
end | end | ||
args | elseif not disallowCats then | ||
table.insert( categories, f:expandTemplate{ title = 'Translation category', args = { 'Pages with missing sprites', project = 0 } } ) | |||
end | end | ||
return p.base( args ) . | return p.base( args ), table.concat( categories, '' ) | ||
end | end | ||
Line 140: | Line 174: | ||
args[1] = args.id or args[1] | args[1] = args.id or args[1] | ||
args.link = link | args.link = args.link or link | ||
args.text = text | args.text = text | ||
Line 147: | Line 181: | ||
function p.doc( f ) | function p.doc( f ) | ||
local args = | local args = f | ||
local | 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 | local getProtection = function( title, action, extra ) | ||
local protections = { 'edit' } | |||
if extra then | |||
table.insert( protections, extra ) | |||
end | |||
local addProtection = function( protection ) | |||
if | if protection == 'autoconfirmed' then | ||
protection = 'editsemiprotected' | |||
elseif protection == 'sysop' then | |||
protection = 'editprotected' | |||
end | end | ||
table.insert( protections, protection ) | |||
end | end | ||
local direct = title.protectionLevels[action] | |||
for _, protection in ipairs( direct ) do | |||
addProtection( protection ) | |||
end | |||
local cascading = title.cascadingProtection.restrictions[action] or {} | |||
if #cascading > 0 then | |||
local | table.insert( protections, 'protect' ) | ||
end | |||
for _, protection in ipairs( cascading ) do | |||
addProtection( protection ) | |||
end | |||
return table.concat( protections, ',' ) | |||
end | |||
local body | |||
if args.refresh then | |||
body = mw.html.create( '' ) | |||
else | |||
local idsTitle = mw.title.new( idsPage ) | |||
local spritesheet = settings.image or settings.name .. 'Sprite.png' | |||
local spriteTitle = mw.title.new( 'File:' .. spritesheet ) | |||
local idsProtection = getProtection( idsTitle, 'edit' ) | |||
local spriteProtection = getProtection( spriteTitle, 'upload', 'upload,reupload' ) | |||
body = mw.html.create( 'div' ):attr( { | |||
id = 'spritedoc', | |||
['data-idspage'] = idsTitle.id, | |||
['data-idsprotection'] = idsProtection, | |||
['data-idstimestamp'] = f:callParserFunction( 'REVISIONTIMESTAMP', idsPage ), | |||
['data-spritesheet'] = spritesheet, | |||
['data-spriteprotection'] = spriteProtection, | |||
['data-pos'] = settings.pos or 1, | |||
['data-refreshtext'] = mw.text.nowiki( '{{#invoke:sprite|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 | end | ||
local nameElem = mw.html.create( 'li' ):addClass( 'spritedoc-name' ) | |||
local codeElem = nameElem:tag( 'code' ):wikitext( data.name ) | |||
if | if idData.deprecated then | ||
codeElem:addClass( 'spritedoc-deprecated' ) | |||
end | end | ||
names:wikitext( tostring( nameElem ) ) | |||
end | end | ||
if args.refresh then | |||
if | return '', tostring( body ) | ||
end | end | ||
return f:callParserFunction( '#widget:Stylesheet', { page = 'SpriteDoc' } ), tostring( body ) | |||
return | |||
end | end | ||
return p | return p |
Revision as of 14:11, 12 May 2017
This module implements {{sprite}}. It should generally be invoked directly on template pages, rather than using the sprite template.
Parent arguments are automatically merged with directly passed arguments (the latter overwriting the former) and all arguments are normalised to trim whitespace and set empty arguments to nil
.
Dependencies
See also
- {{Sprite}}
- {{BiomeSprite}}
- {{BlockSprite}}
- {{CommentSprite}}
- {{EffectSprite}}
- {{EntitySprite}}
- {{EnvSprite}}
- {{ItemSprite}}
- {{SchematicSprite}}
- Module:Sprite
The above documentation is transcluded from Module:Sprite/doc. (edit | history)
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 )
else
f = mw.getCurrentFrame()
end
local categories = {}
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 = ids.ids or ids
local id = mw.text.trim( tostring( args[1] or '' ) )
idData = ids[id] or ids[mw.ustring.lower( id ):gsub( '[%s%+]', '-' )]
end
local title = mw.title.getCurrentTitle()
-- Remove categories on language pages, talk pages, and in User/UserWiki/UserProfile namespaces
local disallowCats = args.nocat or title.isTalkPage or title.nsText:find( '^User' )
if idData then
if type( idData ) == 'table' then
if idData.deprecated and not disallowCats then
table.insert( categories, f:expandTemplate{ title = 'Translation category', args = { 'Pages using deprecated sprite names', project = 0 } } )
end
args.pos = idData.pos
else
args.pos = idData
end
elseif not disallowCats then
table.insert( categories, f:expandTemplate{ title = 'Translation category', args = { 'Pages with missing sprites', project = 0 } } )
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 getProtection = function( title, action, extra )
local protections = { 'edit' }
if extra then
table.insert( protections, extra )
end
local addProtection = function( protection )
if protection == 'autoconfirmed' then
protection = 'editsemiprotected'
elseif protection == 'sysop' then
protection = 'editprotected'
end
table.insert( protections, protection )
end
local direct = title.protectionLevels[action]
for _, protection in ipairs( direct ) do
addProtection( protection )
end
local cascading = title.cascadingProtection.restrictions[action] or {}
if #cascading > 0 then
table.insert( protections, 'protect' )
end
for _, protection in ipairs( cascading ) do
addProtection( protection )
end
return table.concat( protections, ',' )
end
local body
if args.refresh then
body = mw.html.create( '' )
else
local idsTitle = mw.title.new( idsPage )
local spritesheet = settings.image or settings.name .. 'Sprite.png'
local spriteTitle = mw.title.new( 'File:' .. spritesheet )
local idsProtection = getProtection( idsTitle, 'edit' )
local spriteProtection = getProtection( spriteTitle, 'upload', 'upload,reupload' )
body = mw.html.create( 'div' ):attr( {
id = 'spritedoc',
['data-idspage'] = idsTitle.id,
['data-idsprotection'] = idsProtection,
['data-idstimestamp'] = f:callParserFunction( 'REVISIONTIMESTAMP', idsPage ),
['data-spritesheet'] = spritesheet,
['data-spriteprotection'] = spriteProtection,
['data-pos'] = settings.pos or 1,
['data-refreshtext'] = mw.text.nowiki( '{{#invoke:sprite|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