Программное обеспечение вики, MediaWiki, обновлено до версии 1.33. Подробная информация об этом обновлении доступна на Справочной вики Gamepedia. В связи с обновлением возможны некоторые технические неполадки.

We are currently performing an upgrade to our software. This upgrade will bring MediaWiki from version 1.31 to 1.33. While the upgrade is being performed on your wiki it will be in read-only mode. For more information check here.

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

Материал из Minecraft Wiki
Перейти к: навигация, поиск

Этот модуль реализует систему спрайтов Minecraft Wiki. Больше информации расположено на указанной странице и на страницах документации шаблонов спрайтов.

Аргументы страницы, вызвавшей модуль, автоматически объединяются с аргументами, переданными модулю напрямую (последние перезаписывают первые). Также все аргументы нормализуются (при этом удаляются стоящие в начале и в конце пробелы, а пустые аргументы задаются как равные nil).

Зависит от

-- Модуль для отображения иконок из таблиц спрайтов.
-- Внимание: Неосторожные изменения модуля могут привести к проблемам на большом количестве статей!

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
	if setting('страница') ~= '' then
		page = setting('страница')
	elseif setting("главная_страница") ~= '' then
		page = setting("главная_страница")
	end
	if not page then
		page = ''
	end
	
	if not setting( 'nourl' ) and setting( 'url' ) then
		styles[#styles + 1] = 'background-image:' .. ( setting( 'url' ).url or setting( 'url' ) )
	end
	if setting( 'таблстилей' ) then
		sprite:addClass(
			setting( 'имякласса' ) or
			mw.ustring.lower( setting( 'имя' ):gsub( ' ', '-' ) ) .. '-sprite'
		)
	elseif setting('страница') ~= '' or setting("главная_страница") ~= '' then
		-- временная заглушка для GregTech
		styles[#styles + 1] = 'background-image: {{FileUrl|' .. (setting('изобр') or setting('имя') .. page .. 'CSS.png') .. '}}'
	elseif not setting( 'url' ) then
		styles[#styles + 1] = 'background-image:' .. p.getUrl(
			setting( 'изобр' ) or (setting( 'имя' ) .. 'CSS.png')
		).url
	end
	local class = setting( 'класс' )
	if class then
		sprite:addClass( class )
	end
	
	-- Настройки страницы многостраничного спрайта
	local scaleq = 1
	if setting(page) then
		args['масштаб'] = args['масштаб'] or 1
		scaleq = setting(page)['множитель'] or 1
		args['разм'] = setting(page)['разм'] or setting('разм')
		args['формат'] = setting(page)['формат'] or setting('формат')
	else
		scaleq = setting('множитель') or 1
	end
	
	local size = setting('разм') -- размер спрайта в пикселях
	local v_size = setting('верт_разм') or setting('разм') -- размер спрайта в пикселях в высоту
	local pos = math.abs(setting('поз')) - 1 -- положение спрайта в таблице
	local sheetWidth = setting('формат') -- ширина таблицы спрайта в пикселях
	local tiles = sheetWidth / size -- количество спрайтов в одной строке
	local left = pos % tiles * size -- горизонтальная координата спрайта 
	local top = math.floor(pos / tiles ) * v_size -- вертикальная координата спрайта
	local scale = setting('масштаб') * scaleq -- масштаб спрайта (во сколько раз увеличить или уменьшить размер)
	local autoscale = setting('автомасштаб') -- автоматическое применение масштабирования
	local align = setting('выравн') -- выравнивание по вертикали
	
	-- Координаты
	if left > 0 or top > 0 then
		styles[#styles + 1] = 'background-position: -' .. left * scale .. 'px -' .. top * scale .. 'px'
	end

	-- Масштаб
	if not autoscale and scale ~= defaultStyle["масштаб"] then
		styles[#styles + 1] = 'background-size: ' .. sheetWidth * scale .. 'px auto'
	end
	
	-- Размеры спрайта
	if size ~= defaultStyle["разм"] or (not autoscale and scale ~= defaultStyle["масштаб"]) then
		styles[#styles + 1] = 'height: ' .. v_size * scale .. 'px'
		styles[#styles + 1] = 'width: ' .. size * scale .. 'px'
	end
	
	-- Выравнивание
	if align ~= defaultStyle["выравн"] then
		styles[#styles + 1] = 'vertical-align: ' .. align
	end
	
	-- Дополнительный CSS-код, указанный в параметре
	styles[#styles + 1] = setting('css')
	
	-- Применение полученных CSS-стилей к спрайту.
	sprite:cssText(table.concat(styles, ';'))
	
	-- Собственно спрайт.	
	local root
	-- Текстовые данные
	local text = setting('текст')
	local spriteText
	if text and (text ~= 'нет') then
		root = mw.html.create( 'span' ):addClass( 'nowrap' )
		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 ) ~= 'none' then
		-- Внешняя ссылка
		if link:find( '//' ) then
			return '[' .. link .. ' ' .. tostring( root ) .. ']'
		end
		
		-- Внутренняя ссылка. Поддерживается префикс, что полезно при ссылке на модификации.
		local linkPrefix = setting( 'предссылки' ) or ''
		return '[[' .. linkPrefix .. link .. '|' .. tostring( root ) .. ']]'
	end
	
	return tostring( root )
end

-- Данная функция предварительно готовит данные для функции p.base, а затем вызывает её. Её следует вызывать на страницах вики-проекта
-- (через любой из спрайтовых шаблонов)
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"] -- данные по названиям спрайтов и их позициям
	
	local idListName = data['настройки']['списокID']
	local idList = data['IDы']
	if idListName then
		idList = mw.loadData( 'Модуль:' .. idListName )['IDы']
	end
	
	if not idData then
		local name = args["имя"] or data["настройки"]["имя"]
		local id = mw.text.trim( tostring( args[1] or '' ) )
		idData = idList[id] or idList[mw.ustring.lower(id):gsub('[_%-%s%+]+', '-')]
	end
	local title = mw.title.getCurrentTitle()
	
	-- запретить категории соответственно в подстраницах, на страницах обсуждений и в пространствах участников,
	-- а также если установлен параметр «некат»
	local disallowCats = args["некат"] or title.isSubpage or title.isTalkPage or title:inNamespace(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.getUrl( image, query, classname )
	local f = mw.getCurrentFrame()
	local t = {
		url = f:expandTemplate{
			title = 'FileUrl',
			args = { image, query = query }
		},
	}
	if classname and classname ~= '' then
		t.style = f:expandTemplate{
			title = 'FileUrlStyle',
			args = { classname, image, query = query }
		}
	end
	return t
end

function p.getParsedUrlStyle( f )
	local args = f:getParent().args
	local module = args[1]
	return require( 'Модуль:' .. module )["настройки"].url.style
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 idDataSections = data['разделы']
	local idDataList = data['IDы']
	local idDataListOverride = data['настройки']['списокID']
	if idDataListOverride then
		local overrideList = mw.loadData( 'Модуль:' .. idDataListOverride )
		idDataList = overrideList['IDы']
		idDataSections = overrideList['разделы']
	end
	
    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 )
	-- Temporary until this is updated
	local classname = ''
	if data["настройки"]["таблстилей"] then
		classname = data["настройки"]["имякласса"] or
			mw.ustring.lower( data["настройки"]["имя"]:gsub( ' ', '-' ) ) .. '-sprite'
	end
	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-urlfunc'] = "require( [[Модуль:Спрайт]] ).getUrl( '" .. spritesheet .. "', '$1', '" .. classname .. "' )",
		['data-refreshtext'] = mw.text.nowiki( '{{#invoke:Спрайт|doc|' .. dataPage .. '|refresh=1}}' ),
		['data-settings'] = mw.text.jsonEncode( data["настройки"] ),
	} )
	
	local sections = {}
	for _, sectionData in ipairs( idDataSections 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( idDataList ) 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['раздел']]
		if not section then
			error(("У спрайта «%s» (позиция %d) указан некорректный ID раздела: %s"):format(data.name, pos, idData['раздел']))
		end
		
		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.refresh then
		return '', '', tostring( body )
	end
	local styles = f:callParserFunction( '#widget:SpriteDoc.css' )
	return styles, spriteStyle, tostring( body )
end

function p.sortedByIndex(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 translatedData = {}
	local highestPos = 0
	for k, v in pairs(data['IDы']) do
		local pos = v['поз']
		if not translatedData[pos] then
			translatedData[pos] = {['раздел'] = v['раздел']} -- один спрайт не может иметь идентификаторы в разных разделах?
			if pos > highestPos then highestPos = pos; end
		end
		table.insert(translatedData[pos], {['назв'] = k, ['устарел'] = v['устарел']})
	end
	
	for i = 1, highestPos do
		if not translatedData[i] then
			translatedData[i] = {missing = true}
		end
	end
	
	local result = {'{| class="wikitable sortable collapsible collapsed"', "! Позиция !! Раздел !! Спрайт !! Идентификаторы"}
	for i, v in ipairs(translatedData) do
		if not v.missing then
			table.insert(result, "|-")
			table.insert(result, ("| %d"):format(i))
			table.insert(result, ("| %d"):format(v['раздел']))
			table.insert(result, "| " .. p.base({['данные'] = dataPage, ['поз'] = i}))
			table.insert(result, "|")
			for i2, v2 in ipairs(v) do -- ⚠️
				table.insert(result, ("* %s<code>%s</code>"):format(v2['устарел'] == true and "'''(устарел)''' " or "", v2['назв']))
			end
		end
	end
	table.insert(result, "|}")
	
	return table.concat(result, "\n")
end

return p