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

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

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

Зависит от

-- Модуль для отображения иконок из таблиц спрайтов. -- Внимание: Неосторожные изменения модуля могут привести к проблемам на большом количестве статей! local p = {} local h = {} -- Faster than mw.text.trim, but does not have the memory penalty of gsub-based -- solutions function h.fasterTrim(str) local byte = string.byte local startIndex = 0 local space, newline, tab = byte(" \n\t", 1, 3) local strByte repeat startIndex = startIndex + 1 strByte = byte(str, startIndex, startIndex) until (strByte ~= space) and (strByte ~= newline) and (strByte ~= tab) local endIndex = str:len() + 1 repeat endIndex = endIndex - 1 strByte = byte(str, endIndex, endIndex) until (strByte ~= space) and (strByte ~= newline) and (strByte ~= tab) return str:sub(startIndex, endIndex) end function h.getProtection(title, action, extra) local protections = {'edit', extra} 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 -- Создание спрайта function p.base(f) local args = f if f == mw.getCurrentFrame() then args = require('Модуль:ProcessArgs').merge(true) 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 urlSetting = setting( 'url' ) if not setting( 'nourl' ) and urlSetting then styles[#styles + 1] = 'background-image:' .. (urlSetting.url or urlSetting) end if setting( 'таблстилей' ) then sprite:addClass( setting( 'имякласса' ) or mw.ustring.lower( setting( 'имя' ):gsub( ' ', '-' ) ) .. '-sprite' ) elseif page then -- временная заглушка для GregTech styles[#styles + 1] = 'background-image: {{FileUrl|' .. (setting('изобр') or setting('имя') .. page .. 'CSS.png') .. '}}' elseif not urlSetting 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 size -- размер спрайта в пикселях в высоту 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 -- Масштаб local nonDefaultScale = not autoscale and scale ~= defaultStyle["масштаб"] if nonDefaultScale then styles[#styles + 1] = 'background-size: ' .. sheetWidth * scale .. 'px auto' end -- Размеры спрайта if size ~= defaultStyle["разм"] or nonDefaultScale 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 = h.fasterTrim( 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 = h.fasterTrim( 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 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 = h.getProtection( dataTitle, 'edit' ) local spriteProtection = h.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 ) local spriteArgs = { ["поз"] = -1, ["данные"] = dataPage, nourl = spriteStyle ~= '' } for _, data in ipairs( keyedData ) do local idData = data.data local pos = idData['поз'] if not pos then error(string.format('Не найдено позиции у спрайта `%s`', data.name or "?")) end spriteArgs['поз'] = pos local section = sections[idData['раздел']] if not section then error(("У спрайта «%s» (позиция %d) указан некорректный ID раздела: %s"):format(data.name, pos, idData['раздел'])) end spriteArgs['страница'] = 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(spriteArgs) ) 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 = h.fasterTrim( 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 
В данной статье используются материалы из статьи «Модуль:Спрайт» с вики-сайта Minecraft Wiki, расположенного на Фэндоме, и они распространяются согласно лицензии Creative Commons Attribution-NonCommercial-ShareAlike 3.0. Авторы статьи.