Перейти к содержанию

Модуль:Спрайт

Материал из LemonCraft Wiki
Версия от 20:30, 29 апреля 2025; Spark108 (обсуждение | вклад) (1 версия импортирована)
(разн.) ← Предыдущая версия | Текущая версия (разн.) | Следующая версия → (разн.)

Для документации этого модуля может быть создана страница Модуль:Спрайт/doc

local p = {}
function p.base( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Модуль:ProcessArgs' ).merge( true )
	else
		f = mw.getCurrentFrame()
	end
	
	local data = args['данные'] and mw.loadData( 'Модуль:' .. args['данные'] ) or {}
	local settings = data['настройки']
	
	-- Настройки по умолчанию
	local default = {
		['масштаб'] = 1,
		['формат'] = 256,
		['разм'] = 16,
		['поз'] = 1,
		['выравн'] = 'text-top'
	}
	
	local defaultStyle = default
	if settings then
		if not settings['таблстилей'] then
			-- Создание отдельной копии текущих настроек по умолчанию
			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' )
	
	-- Метод CSS от mw.html производит очень медленное экранирование входных данных,
	-- что тормозит работу в два раза. Вместо этого стили будут создаваться вручную
	-- и передаваться через метод cssText, который экранирует только HTML, что быстрее
	local styles = {}
	
	local page = setting( 'страница' ) or setting( 'главная_страница' )
	local classname = setting( 'имякласса' ) or mw.ustring.lower( setting( 'имя' ):gsub( ' ', '-' ) ) .. '-sprite'
	local css_image = "background"
	if setting( 'длямаски' ) then
		classname = classname .. '-mask'
		css_image = "mask"
	end
	
	-- Настройки страницы многостраничного спрайта
	local scaleq
	if setting( page ) then
		args['масштаб'] = args['масштаб'] or 1
		scaleq = setting( page )['множитель'] or setting( 'множитель' ) or 1
		args['ширина'] = setting( page )['ширина'] or setting( page )['разм'] or setting( 'ширина' ) or setting( 'разм' )
		args['высота'] = (setting( page )['высота'] or setting( page )['верт_разм'] or setting( page )['разм'] or setting( 'ширина' ) or setting( 'верт_разм' ) or setting( 'разм' ) )
		args['формат'] = setting( page )['формат'] or setting( 'формат' )
		
		-- класс страницы
		local suffix = setting( page )['суффикскласса']
		if suffix then
			classname = classname .. '-' .. mw.ustring.lower( suffix:gsub( ' ', '-' ) )
		elseif setting( page )['имякласса'] then
			classname = setting( page )['имякласса']
		end
	else
		scaleq = setting( 'множитель' ) or 1
	end
	
	sprite:addClass( classname )
	local class = setting( 'класс' )
	if class then
		sprite:addClass( class )
	end
	
	local width = setting('ширина') or setting( 'разм' ) -- ширина спрайта в пикселях
	local height = setting('высота') or setting( 'верт_разм' ) or setting( 'разм' ) -- высота спрайта в пикселях
	local pos = setting( 'поз' ) - 1 -- положение спрайта в таблице
	local sheetWidth = setting( 'формат' ) -- ширина таблицы спрайта в пикселях
	local scale = setting( 'масштаб' ) -- масштаб спрайта (во сколько раз увеличить или уменьшить размер)
	
	if pos then
		local tiles = sheetWidth / width -- количество спрайтов в одной строке
		local left = pos % tiles * width * scale -- горизонтальная координата спрайта
		local top = math.floor( pos / tiles ) * height * scale -- вертикальная координата спрайта
		
		if css_image == 'mask' then
			styles[#styles + 1] = '-webkit-mask-position:-' .. left .. 'px -' .. top .. 'px'
		end
		styles[#styles + 1] = css_image .. '-position:-' .. left .. 'px -' .. top .. 'px'
	end
	
	local autoScale = setting( 'автомасштаб' ) -- автоматическое применение масштабирования
	if not autoScale and scale ~= defaultStyle['масштаб'] then
		if css_image == 'mask' then
			styles[#styles + 1] = '-webkit-mask-size:' .. sheetWidth * scale .. 'px auto'
		end
		styles[#styles +1] = css_image .. '-size:' .. sheetWidth * scale .. 'px auto'
	end
	if height ~= defaultStyle['разм'] or width ~= defaultStyle['разм'] or ( not autoScale and scale ~= defaultStyle['масштаб'] ) then
		styles[#styles + 1] = 'height:' .. height * scale .. 'px'
		styles[#styles + 1] = 'width:' .. width * scale .. 'px'
	end
	
	local align = setting( 'выравн' ) -- выравнивание по вертикали
	if align ~= defaultStyle['выравн'] then
		styles[#styles + 1] = '--sprite-vertical-align:' .. align
	end
	styles[#styles + 1] = setting( 'css' )
	
	sprite:cssText( table.concat( styles, ';' ) )
	
	local text = setting( 'текст' )
	local root
	local spriteText
	if text and (text ~= 'нет') then
		if not args['перенос'] then
			root = mw.html.create( 'span' ):addClass( 'nowrap' )
		end
		spriteText = mw.html.create( 'span' ):addClass( 'sprite-text' ):wikitext( text )
	end
	
	local title = setting( 'назв' )
	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( 'ссылка' ) or ''
	if link ~= '' and mw.ustring.lower( link ) ~= 'нет' then
		-- Внешняя ссылка
		if link:find( '//' ) then
			return '[' .. link .. ' ' .. tostring( root ) .. ']'
		end
		
		-- Внутренняя ссылка
		local linkPrefix = setting( 'предссылки' ) or ''
		if mw.ustring.lower(linkPrefix) == 'нет' then
			linkPrefix = ''
		end
		return '[[' .. linkPrefix .. link .. '|' .. tostring( root ) .. ']]'
	end
	
	return tostring( root )
end

function p.sprite( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Модуль:ProcessArgs' ).merge( true )
	else
		f = mw.getCurrentFrame()
	end
	
	local data = args['данные'] and mw.loadData( 'Модуль:' .. args['данные'] ) or {}
	local categories = {}
	local idData = args['данныеID']
	if not idData then
		local name = args['имя'] or data['настройки']['имя']
		local id = mw.text.trim( tostring( args[1] or '' ) )
		idData = data['IDы'][id] or data['IDы'][mw.ustring.lower( id ):gsub( '[_%s%+]', '-' )]
	end
	
	local title = mw.title.getCurrentTitle()
	-- Отключение категоризации на страницах обсуждения и в пространстве имён «Участник»
	local disallowCats = args['некат'] or title.isTalkPage or title.namespace == 2
	if idData then
		if idData['устарел'] then
			args['класс'] = ( args['класс'] or '' ) .. ' sprite-deprecated'
			if not disallowCats then
				categories[#categories + 1] = '[[Категория:Страницы с устаревшими названиями спрайтов]]'
			end
		end
		
		args['поз'] = idData['поз']
		args['страница'] = idData['страница']
	elseif not disallowCats then
		categories[#categories + 1] = '[[Категория:Страницы с отсутствующими спрайтами]]'
	end
	
	return p.base( args ), table.concat( categories )
end

function p.link( f )
	local args = f
	if f == mw.getCurrentFrame() then
		args = require( 'Модуль: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
	if not args['безтекста'] then
		text = args['текст'] or args[2] or link
	end
	
	args[1] = args['ID'] or args[1]
	args['ссылка'] = args['ссылка'] or link
	args['текст'] = 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 dataPage = mw.text.trim( args[1] )
	local data = mw.loadData( 'Модуль:' .. dataPage )
	
	local getProtection = function( title, action, extra )
		local protections = { 'edit' }
		if extra then
			protections[#protections + 1] = extra
		end
		
		local addProtection = function( protection )
			if protection == 'autoconfirmed' then
				protection = 'editsemiprotected'
			elseif protection == 'sysop' then
				protection = 'editprotected'
			end
			
			protections[#protections + 1] = protection
		end
		
		local direct = title.protectionLevels[action] or {}
		for _, protection in ipairs( direct ) do
			addProtection( protection )
		end
		local cascading = title.cascadingProtection.restrictions[action] or {}
		if #cascading > 0 then
			protections[#protections + 1] = 'protect'
		end
		for _, protection in ipairs( cascading ) do
			addProtection( protection )
		end
		
		return table.concat( protections, ',' )
	end
	
	local spriteStyle = ''
	if data['настройки'].url and data['настройки'].url.style then
		spriteStyle = data['настройки'].url.style
	end
	
	local dataTitle = mw.title.new( 'Модуль:' .. dataPage )
	-- Временно, пока не будет обновлено
	local spritesheet = data['настройки']['изобр'] or data['настройки']['имя'] .. 'CSS.png'
	local spriteTitle = mw.title.new( 'Файл:' .. spritesheet )
	local dataProtection = getProtection( dataTitle, 'edit' )
	local spriteProtection = getProtection( spriteTitle, 'upload', 'upload,reupload' )
	local body = mw.html.create( 'div' ):attr( {
		id = 'spritedoc',
		['data-dataprotection'] = dataProtection,
		['data-datatimestamp'] = f:callParserFunction( 'REVISIONTIMESTAMP', 'Модуль:' .. dataPage ),
		['data-datapage'] = 'Модуль:' .. dataPage,
		['data-spritesheet'] = spritesheet,
		['data-spriteprotection'] = spriteProtection,
		['data-refreshtext'] = mw.text.nowiki( '{{#invoke:Спрайт|doc|' .. dataPage .. '|refresh=1}}' ),
		['data-settings'] = mw.text.jsonEncode( data['настройки'] ),
	} )
	
	local sections = {}
	for _, sectionData in ipairs( data['разделы'] or { ['назв'] = 'Некатегоризованные' } ) do
		local sectionTag = body:tag( 'div' ):addClass( 'spritedoc-section' ):attr( 'data-section-id', sectionData.ID )
		sectionTag:tag( 'h3' ):wikitext( sectionData['назв'] )
		sections[sectionData.ID] = { boxes = sectionTag:tag( 'ul' ):addClass( 'spritedoc-boxes' ) }
	end
	
	local keyedData = {}
	local i = 1
	for name, idData in pairs( data['IDы'] ) do
		keyedData[i] = {
			sortKey = mw.ustring.lower( 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['поз']
		local section = sections[idData['раздел']]
		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, ['данные'] = dataPage, nourl = spriteStyle ~= '' } )
			
			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['устарел'] then
			codeElem:addClass( 'spritedoc-deprecated' )
		end
		names:wikitext( tostring( nameElem ) )
	end
	
	if args['обновить'] then
		return '', '', tostring( body )
	end
	local styles = f:extensionTag( 'templatestyles', '', { src = 'Спрайт/doc.css' } )
	return styles, spriteStyle, tostring( body )
end
return p