欢迎来到奇葩栖息地!欢迎加入Discord服务器:XfrfHCzfbW请先至特殊:参数设置验证邮箱后再进行编辑。特殊:参数设置挑选自己想要使用的小工具!不会编辑?请至这里学习Wikitext语法。

距离淮安市2022年中考还有142天。

模块:Sprite

来自奇葩栖息地

此模块用于实现{{sprite}}。此模块应该用于在模板页面引用,而不是用模板代码。

父参数已经和直接传递参数合并(后者覆盖前者),并且所有的参数在处理时已经标准化并去除空格,空的参数值将会被设置为nil

依赖项

  1local p = {}
  2function p.base( f )
  3	local args = f
  4	if f == mw.getCurrentFrame() then 
  5		args = require( 'Module:ProcessArgs' ).merge( true )
  6	else
  7		f = mw.getCurrentFrame()
  8	end
  9	
 10	local data = args.data and mw.loadData( 'Module:' .. args.data ) or {}
 11	local settings = data.settings
 12	
 13	-- Default settings
 14	local default = {
 15		scale = 1,
 16		sheetsize = 256,
 17		size = 16,
 18		pos = 1,
 19		align = 'text-top'
 20	}
 21	
 22	local defaultStyle = default
 23	if settings then
 24		if not settings.stylesheet then
 25			-- Make a separate clone of the current default settings
 26			defaultStyle = mw.clone( default )
 27		end
 28		for k, v in pairs( settings ) do
 29			default[k] = v
 30		end
 31	end
 32	
 33	local setting = function( arg )
 34		return args[arg] or default[arg]
 35	end
 36	
 37	local sprite = mw.html.create( 'span' ):addClass( 'sprite' )
 38	
 39	-- mw.html's css method performs very slow escaping, which doubles the time it takes
 40	-- to run, so we'll construct the styles manually, and put them in the cssText
 41	-- method, which only does html escaping (which isn't slow)
 42	local styles = {}
 43	
 44	if not setting( 'nourl' ) and setting( 'url' ) then
 45		styles[#styles + 1] = 'background-image:' .. ( setting( 'url' ).url or setting( 'url' ) )
 46	end
 47	if setting( 'stylesheet' ) then
 48		sprite:addClass(
 49			setting( 'classname' ) or
 50			mw.ustring.lower( setting( 'name' ):gsub( ' ', '-' ) ) .. '-sprite'
 51		)
 52	elseif not setting( 'url' ) then
 53		styles[#styles + 1] = 'background-image:' .. p.getUrl(
 54			setting( 'image' ) or setting( 'name' ) .. 'Sprite.png'
 55		).url
 56	end
 57	local class = setting( 'class' )
 58	if class then
 59		sprite:addClass( class )
 60	end
 61	
 62	local size = setting( 'size' )
 63	local sheetWidth = setting( 'sheetsize' )
 64	local tiles = sheetWidth / size
 65	local pos = setting( 'pos' ) - 1
 66	local scale = setting( 'scale' )
 67	local autoScale = setting( 'autoscale' )
 68	
 69	if pos then
 70		local left = pos % tiles * size * scale
 71		local top = math.floor( pos / tiles ) * size * scale
 72		styles[#styles + 1] = 'background-position:-' .. left .. 'px -' .. top .. 'px'
 73	end
 74	
 75	if not autoScale and scale ~= defaultStyle.scale then
 76		styles[#styles + 1] = 'background-size:' .. sheetWidth * scale .. 'px auto'
 77	end
 78	if size ~= defaultStyle.size or ( not autoScale and scale ~= defaultStyle.scale ) then
 79		styles[#styles + 1] = 'height:' .. size * scale .. 'px'
 80		styles[#styles + 1] = 'width:' .. size * scale .. 'px'
 81	end
 82	
 83	local align = setting( 'align' )
 84	if align ~= defaultStyle.align then
 85		styles[#styles + 1] = 'vertical-align:' .. align
 86	end
 87	styles[#styles + 1] = setting( 'css' )
 88	
 89	sprite:cssText( table.concat( styles, ';' ) )
 90	
 91	local text = setting( 'text' )
 92	local root
 93	local spriteText
 94	if text then
 95		if not args['wrap'] then
 96			root = mw.html.create( 'span' ):addClass( 'nowrap' )
 97		end
 98		spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( text )
 99	end
100	
101	local title = setting( 'title' )
102	if title then
103		( root or sprite ):attr( 'title', title )
104	end
105	
106	if not root then
107		root = mw.html.create( '' )
108	end
109	root:node( sprite )
110	if spriteText then
111		root:node( spriteText )
112	end
113	
114	local link = setting( 'link' ) or ''
115	if link ~= '' and mw.ustring.lower( link ) ~= 'none' then
116		-- External link
117		if link:find( '//' ) then
118			return '[' .. link .. ' ' .. tostring( root ) .. ']'
119		end
120		
121		-- Internal link
122		local linkPrefix = setting( 'linkprefix' ) or ''
123		return '[[' .. linkPrefix .. link .. '|' .. tostring( root ) .. ']]'
124	end
125	
126	return tostring( root )
127end
128
129function p.sprite( f )
130	local args = f
131	if f == mw.getCurrentFrame() then
132		args = require( 'Module:ProcessArgs' ).merge( true )
133	else
134		f = mw.getCurrentFrame()
135	end
136	
137	local data = args.data and mw.loadData( 'Module:' .. args.data ) or {}
138	local categories = {}
139	local idData = args.iddata
140	if not idData then
141		local name = args.name or data.settings.name
142		local id = mw.text.trim( tostring( args[1] or '' ) )
143		idData = data.ids[id] or data.ids[mw.ustring.lower( id ):gsub( '[%s%+]', '-' )]
144	end
145	
146	local title = mw.title.getCurrentTitle()
147	-- Remove categories on language pages, talk pages, and in User/UserWiki/UserProfile namespaces
148	local disallowCats = args.nocat or title.isTalkPage or title.nsText:find( '^User' )
149	if idData then
150		if idData.deprecated then
151			args.class = ( args.class or '' ) .. ' sprite-deprecated'
152			if not disallowCats then
153				categories[#categories + 1] = f:expandTemplate{ title = 'Translation category', args = { 'Pages using deprecated sprite names', project = 0 } }
154			end
155		end
156		
157		args.pos = idData.pos
158	elseif not disallowCats then
159		categories[#categories + 1] = f:expandTemplate{ title = 'Translation category', args = { 'Pages with missing sprites', project = 0 } }
160	end
161	
162	return p.base( args ), table.concat( categories )
163end
164
165function p.link( f )
166	local args = f
167	if f == mw.getCurrentFrame() then
168		args = require( 'Module:ProcessArgs' ).merge( true )
169	end
170	
171	local link = args[1]
172	if args[1] and not args.id then
173		link = args[1]:match( '^(.-)%+' ) or args[1]
174	end
175	local text
176	if not args.notext then
177		text = args.text or args[2] or link
178	end
179	
180	args[1] = args.id or args[1]
181	args.link = args.link or link
182	args.text = text
183	
184	return p.sprite( args )
185end
186
187function p.getUrl( image, query, classname )
188	local f = mw.getCurrentFrame()
189	local t = {
190		url = f:expandTemplate{
191			title = 'FileUrl',
192			args = { image, query = query }
193		},
194	}
195	if classname and classname ~= '' then
196		t.style = f:expandTemplate{
197			title = 'FileUrlStyle',
198			args = { classname, image, query = query }
199		}
200	end
201	return t
202end
203
204function p.getParsedUrlStyle( f )
205	local args = f:getParent().args
206	local module = args[1]
207	return require( 'Module:' .. module ).settings.url.style
208end
209
210function p.doc( f )
211	local args = f
212	if f == mw.getCurrentFrame() then
213		args = f.args
214	else
215		f = mw.getCurrentFrame()
216	end
217	local dataPage = mw.text.trim( args[1] )
218	local data = mw.loadData( 'Module:' .. dataPage )
219	
220	local getProtection = function( title, action, extra )
221		local protections = { 'edit' }
222		if extra then
223			protections[#protections + 1] = extra
224		end
225		
226		local addProtection = function( protection )
227			if protection == 'autoconfirmed' then
228				protection = 'editsemiprotected'
229			elseif protection == 'sysop' then
230				protection = 'editprotected'
231			end
232			
233			protections[#protections + 1] = protection
234		end
235		
236		local direct = title.protectionLevels[action] or {}
237		for _, protection in ipairs( direct ) do
238			addProtection( protection )
239		end
240		local cascading = title.cascadingProtection.restrictions[action] or {}
241		if #cascading > 0 then
242			protections[#protections + 1] = 'protect'
243		end
244		for _, protection in ipairs( cascading ) do
245			addProtection( protection )
246		end
247		
248		return table.concat( protections, ',' )
249	end
250	
251	local spriteStyle = ''
252	if data.settings.url and data.settings.url.style then
253		spriteStyle = data.settings.url.style
254	end
255	
256	local dataTitle = mw.title.new( 'Module:' .. dataPage )
257	-- Temporary until this is updated
258	local classname = ''
259	if data.settings.stylesheet then
260		classname = data.settings.classname or
261			mw.ustring.lower( data.settings.name:gsub( ' ', '-' ) ) .. '-sprite'
262	end
263	local spritesheet = data.settings.image or data.settings.name .. 'Sprite.png'
264	local spriteTitle = mw.title.new( 'File:' .. spritesheet )
265	local dataProtection = getProtection( dataTitle, 'edit' )
266	local spriteProtection = getProtection( spriteTitle, 'upload', 'upload,reupload' )
267	local body = mw.html.create( 'div' ):attr( {
268		id = 'spritedoc',
269		['data-dataprotection'] = dataProtection,
270		['data-datatimestamp'] = f:callParserFunction( 'REVISIONTIMESTAMP', 'Module:' .. dataPage ),
271		['data-datapage'] = 'Module:' .. dataPage,
272		['data-spritesheet'] = spritesheet,
273		['data-spriteprotection'] = spriteProtection,
274		['data-urlfunc'] = "require( [[Module:Sprite]] ).getUrl( '" .. spritesheet .. "', '$1', '" .. classname .. "' )",
275		['data-refreshtext'] = mw.text.nowiki( '{{#invoke:sprite|doc|' .. dataPage .. '|refresh=1}}' ),
276		['data-settings'] = mw.text.jsonEncode( data.settings ),
277	} )
278	
279	local sections = {}
280	for _, sectionData in ipairs( data.sections or { name = 'Uncategorized' } ) do
281		local sectionTag = body:tag( 'div' ):addClass( 'spritedoc-section' ):attr( 'data-section-id', sectionData.id )
282		sectionTag:tag( 'h3' ):wikitext( sectionData.name )
283		sections[sectionData.id] = { boxes = sectionTag:tag( 'ul' ):addClass( 'spritedoc-boxes' ) }
284	end
285	
286	local keyedData = {}
287	local i = 1
288	for name, idData in pairs( data.ids ) do
289		keyedData[i] = {
290			sortKey = mw.ustring.lower( name ),
291			name = name,
292			data = idData
293		}
294		i = i + 1
295	end
296	table.sort( keyedData, function( a, b )
297		return a.sortKey < b.sortKey
298	end )
299	
300	for _, data in ipairs( keyedData ) do
301		local idData = data.data
302		local pos = idData.pos
303		local section = sections[idData.section]
304		local names = section[pos]
305		if not names then
306			local box = section.boxes:tag( 'li' ):addClass( 'spritedoc-box' ):attr( 'data-pos', pos )
307			box:tag( 'div' ):addClass( 'spritedoc-image' )
308				:wikitext( p.base{ pos = pos, data = dataPage, nourl = spriteStyle ~= '' } )
309			
310			names = box:tag( 'ul' ):addClass( 'spritedoc-names' )
311			section[pos] = names
312		end
313		local nameElem = mw.html.create( 'li' ):addClass( 'spritedoc-name' )
314		local codeElem = nameElem:tag( 'code' ):wikitext( data.name )
315		
316		if idData.deprecated then
317			codeElem:addClass( 'spritedoc-deprecated' )
318		end
319		names:wikitext( tostring( nameElem ) )
320	end
321	
322	if args.refresh then
323		return '', '', tostring( body )
324	end
325	local styles = f:callParserFunction( '#widget:SpriteDoc.css' )
326	return styles, spriteStyle, tostring( body )
327end
328return p