Модуль:Инвентарный слот — различия между версиями
MailGik (обсуждение | вклад) |
Popstop (обсуждение | вклад) м |
||
(не показано 307 промежуточных версий 2 участников) | |||
Строка 1: | Строка 1: | ||
------------------------------------------------------------------- | ------------------------------------------------------------------- | ||
− | --- Модуль для отображения инвентарных слотов в | + | --- Модуль для отображения инвентарных слотов в Minecraft Wiki. |
------------------------------------------------------------------- | ------------------------------------------------------------------- | ||
local p = {} | local p = {} | ||
− | |||
-- Список приставок к названиям, обрабатываемых другими модулями. | -- Список приставок к названиям, обрабатываемых другими модулями. | ||
-- Так будет легче, например, убирать их из целей ссылок. | -- Так будет легче, например, убирать их из целей ссылок. | ||
Строка 12: | Строка 11: | ||
'Повреждённый', 'Повреждённая', 'Повреждённое', 'Повреждённые' -- использование Ё обязательно | 'Повреждённый', 'Повреждённая', 'Повреждённое', 'Повреждённые' -- использование Ё обязательно | ||
} | } | ||
+ | |||
+ | p.modAliases = mw.loadData("Модуль:Модификации") | ||
--- Создание слота | --- Создание слота | ||
Строка 23: | Строка 24: | ||
-- Первый аргумент | -- Первый аргумент | ||
args[1] = mw.text.trim(args[1] or '') | args[1] = mw.text.trim(args[1] or '') | ||
− | + | ||
− | --- Псевдонимы | + | --- Псевдонимы оригинальной игры |
− | |||
local aliases = mw.loadData('Модуль:Инвентарный слот/Псевдонимы') | local aliases = mw.loadData('Модуль:Инвентарный слот/Псевдонимы') | ||
− | + | local frames = {} | |
− | + | for frame in mw.text.gsplit( args[1], '%s*;%s*' ) do | |
− | + | ||
− | + | local frameParts = p.getParts( frame, args["мод"] ) | |
− | + | local id = frameParts.name | |
− | + | -- if frameParts.mod then | |
− | + | -- id = frameParts.mod .. ':' .. id | |
− | + | -- end | |
− | + | ||
− | + | --- Загрузка списка псевдонимов к модам | |
− | + | local modAliases | |
− | + | if frameParts.mod then | |
− | + | if mw.title.new('Модуль:ИнвСпрайт/' .. frameParts.mod).exists then | |
− | + | modAliases = mw.loadData('Модуль:ИнвСпрайт/' .. frameParts.mod)["модпсевдонимы"] | |
− | + | if modAliases and mw.title.new('Модуль:' .. modAliases).exists then | |
− | + | modAliases = mw.loadData('Модуль:' .. modAliases) | |
− | + | end | |
− | + | end | |
− | + | end | |
− | + | ||
− | + | local alias = nil | |
− | + | if frameParts.mod then | |
− | + | if modAliases and modAliases[id] then | |
− | + | ||
− | + | --- ['имя'] = '[титл]:имя[доп. текст]' | |
− | + | ||
− | + | local title = mw.ustring.match ( modAliases[id], '^%[([^%]]+)%]' ) | |
− | + | if title then | |
− | + | local aaa = mw.ustring.match ( modAliases[id], '^%[[^%]]+%](.+)$' ) | |
+ | if aaa then | ||
+ | alias = '[' .. title .. ']' .. frameParts.mod .. ':' .. aaa | ||
+ | else | ||
+ | alias = '[' .. title .. ']' .. frameParts.mod .. ':' .. frameParts.name | ||
+ | end | ||
+ | else | ||
+ | alias = frameParts.mod .. ':' .. modAliases[id] | ||
+ | end | ||
+ | end | ||
+ | elseif aliases and aliases[id] then | ||
+ | alias = aliases[id] | ||
+ | end | ||
+ | |||
+ | if alias then | ||
+ | table.insert( frames, p.expandAlias( frameParts, alias ) ) | ||
+ | else | ||
+ | table.insert( frames, frame ) | ||
end | end | ||
− | |||
− | |||
end | end | ||
+ | args[1] = table.concat( frames, ';' ) | ||
--- Построение спрайта | --- Построение спрайта | ||
Строка 111: | Строка 127: | ||
local description = parts.text | local description = parts.text | ||
− | local img, idData | + | local img, idData, en_name |
if mod then | if mod then | ||
local modData = modIds[mod] | local modData = modIds[mod] | ||
if not modData and mw.title.new('Модуль:ИнвСпрайт/' .. mod .. '/ID').exists then | if not modData and mw.title.new('Модуль:ИнвСпрайт/' .. mod .. '/ID').exists then | ||
− | modData = mw.loadData('Модуль:ИнвСпрайт/' .. mod .. '/ID') | + | modData = mw.loadData('Модуль:ИнвСпрайт/' .. mod .. '/ID')["IDы"] |
modIds[mod] = modData | modIds[mod] = modData | ||
end | end | ||
if modData and modData[name] then | if modData and modData[name] then | ||
idData = modData[name] | idData = modData[name] | ||
+ | en_name = idData["en"] | ||
else | else | ||
img = name .. ' (' .. mod .. ')' | img = name .. ' (' .. mod .. ')' | ||
Строка 128: | Строка 145: | ||
img = name | img = name | ||
end | end | ||
− | + | ||
+ | local vanilla = {v = 1, vanilla = 1, mc = 1, minecraft = 1} | ||
local link = args["ссылка"] or '' | local link = args["ссылка"] or '' | ||
if link == '' then | if link == '' then | ||
Строка 134: | Строка 152: | ||
link = mod .. '/' .. name | link = mod .. '/' .. name | ||
else | else | ||
− | link = | + | link = nil |
end | end | ||
elseif mw.ustring.lower(link) == 'нет' then | elseif mw.ustring.lower(link) == 'нет' then | ||
Строка 143: | Строка 161: | ||
end | end | ||
− | + | local formattedTitle | |
− | |||
local plainTitle | local plainTitle | ||
if title == '' then | if title == '' then | ||
Строка 153: | Строка 170: | ||
local formatPattern = '&[0-9a-fk-or]' | local formatPattern = '&[0-9a-fk-or]' | ||
if mw.ustring.match(plainTitle, formatPattern) then | if mw.ustring.match(plainTitle, formatPattern) then | ||
− | + | formattedTitle = title | |
plainTitle = mw.ustring.gsub(plainTitle, formatPattern, '') | plainTitle = mw.ustring.gsub(plainTitle, formatPattern, '') | ||
end | end | ||
Строка 164: | Строка 181: | ||
elseif link then | elseif link then | ||
if img then | if img then | ||
− | + | formattedTitle = '' | |
else | else | ||
plainTitle = '' | plainTitle = '' | ||
Строка 170: | Строка 187: | ||
end | end | ||
− | |||
item:attr{ | item:attr{ | ||
['data-minetip-title'] = formattedTitle, | ['data-minetip-title'] = formattedTitle, | ||
− | ['data-minetip-text'] = description | + | ['data-minetip-text'] = description, |
+ | ['data-modinfo-text'] = mod, | ||
+ | ['data-minetip-lowtitle'] = en_name | ||
} | } | ||
− | |||
if img then | if img then | ||
-- & is re-escaped because mw.html treats attributes | -- & is re-escaped because mw.html treats attributes | ||
-- as plain text, but MediaWiki doesn't | -- as plain text, but MediaWiki doesn't | ||
− | local escapedTitle = | + | local escapedTitle = ( plainTitle or '' ):gsub( '&', '&' ) |
item:addClass('invslot-item-image') | item:addClass('invslot-item-image') | ||
:wikitext('[[Файл:Grid ', img, '.png|32x32px|link=', link or '', '|', escapedTitle, ']]') | :wikitext('[[Файл:Grid ', img, '.png|32x32px|link=', link or '', '|', escapedTitle, ']]') | ||
Строка 194: | Строка 211: | ||
item:wikitext('[[', link, '|') | item:wikitext('[[', link, '|') | ||
end | end | ||
− | local image, spriteCat = sprite{ | + | |
− | + | local image, spriteCat; | |
− | + | if not mod then | |
− | } | + | image, spriteCat = sprite{ |
+ | ["данныеID"] = idData, ["назв"] = plainTitle, | ||
+ | ["изобр"] = image, ["настройки"] = 'ИнвСпрайт' | ||
+ | } | ||
+ | else | ||
+ | image, spriteCat = sprite{ | ||
+ | ["данныеID"] = idData, ["назв"] = plainTitle, | ||
+ | ["изобр"] = image, ["настройки"] = 'ИнвСпрайт/' .. mod | ||
+ | } | ||
+ | end | ||
item:node(image) | item:node(image) | ||
category = spriteCat | category = spriteCat | ||
Строка 239: | Строка 265: | ||
function p.expandAlias( frameParts, alias ) | function p.expandAlias( frameParts, alias ) | ||
-- If the frame has no parts, we can just return the alias as-is | -- If the frame has no parts, we can just return the alias as-is | ||
− | if not frameParts.title and not frameParts.mod and not frameParts.num and not frameParts.text then | + | --[[if not frameParts.title and not frameParts.mod and not frameParts.num and not frameParts.text then |
return alias | return alias | ||
− | end | + | end--]] |
local expandedFrames = {} | local expandedFrames = {} | ||
Строка 259: | Строка 285: | ||
return table.concat(expandedFrames, ';') | return table.concat(expandedFrames, ';') | ||
end | end | ||
+ | |||
function p.getParts(frame, mod) | function p.getParts(frame, mod) | ||
+ | ----Функция получает название предмета в формате "[титл]мод:имя[доп.текст],число" | ||
+ | ----parts.title = титл, название предмета при наведении | ||
+ | ----parts.mod = мод | ||
+ | ----parts.name = имя | ||
+ | ----parts.text = текст, дополнительный текст при наведении на предмет | ||
+ | ----parts.num = число | ||
+ | |||
local parts = {} | local parts = {} | ||
parts.title = mw.ustring.match(frame, '^%[%s*([^%]]+)%s*%]') | parts.title = mw.ustring.match(frame, '^%[%s*([^%]]+)%s*%]') | ||
− | parts.mod = mw.text.trim(mw.ustring.match(frame, | + | local modPattern |
− | + | if mw.ustring.match(frame, '^%[.*%]([a-zA-Zа-яА-Я0-9ёЁé _%-\']+):') then | |
+ | modPattern = '^%[.*%]([a-zA-Zа-яА-Я0-9ёЁé _%-\']+):' | ||
+ | else | ||
+ | modPattern = '^([a-zA-Zа-яА-Я0-9ёЁé _%-\']+):' | ||
+ | end | ||
+ | |||
+ | parts.mod = mw.text.trim(mw.ustring.match(frame, modPattern) or mod or '') ---- Получаем название мода | ||
+ | |||
local vanilla = {v = 1, vanilla = 1, mc = 1, minecraft = 1} | local vanilla = {v = 1, vanilla = 1, mc = 1, minecraft = 1} | ||
− | if parts.mod == '' or vanilla[mw.ustring.lower(parts.mod)] then | + | if parts.mod == '' or vanilla[mw.ustring.lower(parts.mod)] then |
+ | link = nil | ||
parts.mod = nil | parts.mod = nil | ||
+ | else | ||
+ | if p.modAliases[parts.mod] then | ||
+ | parts.mod = p.modAliases[parts.mod] | ||
+ | end | ||
+ | parts.mod = mw.ustring.gsub(parts.mod,'_',' ') | ||
end | end | ||
− | + | local _, nameStartV = mw.ustring.find( frame, '^%[[^%]]*%]' ) | |
− | local | + | local nameStart = ( ({mw.ustring.find( frame, modPattern )})[2] or nameStartV or 0 ) + 1 |
if nameStart - 1 == #frame then | if nameStart - 1 == #frame then | ||
nameStart = 1 | nameStart = 1 | ||
end | end | ||
− | parts.name = mw.text.trim(mw.ustring.sub(frame, nameStart, (mw.ustring.find(frame, '[,%[]', nameStart) or 0) - 1)) | + | parts.name = mw.text.trim( mw.ustring.sub( frame, nameStart, ( mw.ustring.find( frame, '[,%[]', nameStart ) or 0 ) - 1 ) ) |
parts.num = math.floor(mw.ustring.match(frame, ',%s*(%d+)') or 0) | parts.num = math.floor(mw.ustring.match(frame, ',%s*(%d+)') or 0) | ||
Строка 283: | Строка 330: | ||
parts.text = mw.ustring.match(frame, '%[%s*([^%]]+)%s*%]$') | parts.text = mw.ustring.match(frame, '%[%s*([^%]]+)%s*%]$') | ||
− | + | ||
return parts | return parts | ||
end | end | ||
return p | return p |
Текущая версия на 08:11, 16 октября 2018
Этот модуль используется для изображения инвентарных слотов с изображениями блоков и предметов. Эти слоты по виду подобны тем, что имеются в игре Minecraft (при стандартном пакете ресурсов). Изображение каждого предмета достаётся из таблицы спрайтов, а если оно там отсутствует — из файла с полным названием в формате Файл:Grid Название предмета [(Модификация игры, если указана)].png
[1]
Модуль рекомендуется использовать в других модулях напрямую (через require("Модуль:Инвентарный слот")
), а вне их — через шаблон {{Инвентарный слот}}.
Содержание
Использование
- Смотрите также: Справка:Модули
Внутри других модулей этот модуль включается через функцию Lua require
: require("Модуль:Инвентарный слот")
, которая возвращает ассоциативный массив (таблицу) с функциями и параметрами. Основной функцией является slot, именно её и следует вызывать, чтобы отобразить слот.
В других страницах модуль (а конкретно её функция slot) используется преимущественно через шаблон {{Инвентарный слот}}, который вызывает программу через конструкцию {{#invoke: Инвентарный слот|slot}}
(при этом параметры шаблона передаются модулю неявно). Именно эту конструкцию необходимо использовать, если модуль нужно вызвать из обычной страницы напрямую (вот только зачем?).
Параметры
Модуль поддерживает следующие параметры:
Название | Описание | Значение по умолчанию |
---|---|---|
Основные параметры | ||
1 [2] |
Указывает название блока или предмета (или псевдоним). Можно указывать несколько предметов (до 16), отделяя их точкой с запятой. После названия через запятую можно указывать число предметов в стопке. Перед же названием можно указать в [квадратных скобках] иной всплывающий текст (по умолчанию он такой же, как и название предмета, если только не переопределён псевдонимом). | Пустое (тогда слот создаётся пустым) |
назв |
Переопределяет всплывающий текст для предметов. Следует обратить внимание, что он имеет более низкий приоритет, чем переопределение с помощью квадратных скобок, а значит, если используются оба метода сразу, отображён будет текст из скобок. | Пустое (тогда всплывающие тексты остаются нетронутыми) |
ссылка |
Определяет, на какую страницу ссылаются изображения. | Пустое (тогда изображения ссылаются на одноимённые с ними страницы) |
Зависимости
- Система спрайтов:
- Модуль:Спрайт — главный модуль системы спрайтов.
- Модуль:ИнвСпрайт — данные по используемой модулем таблицы спрайтов ИнвСпрайт.
- Модуль:ИнвСпрайт/ID — названия поддерживаемых предметов.
- Модуль:Инвентарный слот/Псевдонимы — псевдонимы для поддерживаемых названий.
Примечания
- ↑ Курсивом выделен текст, который заменяется на соответствующее значение. В [квадратных скобках] указан фрагмент, который не всегда присутствует.
- ↑ Параметры с числовыми названиями являются порядковыми и обычно указываются без названия, которое тогда соответствует порядковому номеру среди таких аргументов.
Расположенная выше документация включена из Модуль:Инвентарный слот/док.
-------------------------------------------------------------------
--- Модуль для отображения инвентарных слотов в Minecraft Wiki.
-------------------------------------------------------------------
local p = {}
-- Список приставок к названиям, обрабатываемых другими модулями.
-- Так будет легче, например, убирать их из целей ссылок.
-- ВНИМАНИЕ: указывайте все варианты склонения по родам и числам.
p.prefixes = {
'Любой', 'Любая', 'Любое', 'Любые',
'Повреждённый', 'Повреждённая', 'Повреждённое', 'Повреждённые' -- использование Ё обязательно
}
p.modAliases = mw.loadData("Модуль:Модификации")
--- Создание слота
function p.slot(f)
--- Получение аргументов
local args = f.args or f
if f == mw.getCurrentFrame() and args[1] == nil then
args = f:getParent().args
end
-- Первый аргумент
args[1] = mw.text.trim(args[1] or '')
--- Псевдонимы оригинальной игры
local aliases = mw.loadData('Модуль:Инвентарный слот/Псевдонимы')
local frames = {}
for frame in mw.text.gsplit( args[1], '%s*;%s*' ) do
local frameParts = p.getParts( frame, args["мод"] )
local id = frameParts.name
-- if frameParts.mod then
-- id = frameParts.mod .. ':' .. id
-- end
--- Загрузка списка псевдонимов к модам
local modAliases
if frameParts.mod then
if mw.title.new('Модуль:ИнвСпрайт/' .. frameParts.mod).exists then
modAliases = mw.loadData('Модуль:ИнвСпрайт/' .. frameParts.mod)["модпсевдонимы"]
if modAliases and mw.title.new('Модуль:' .. modAliases).exists then
modAliases = mw.loadData('Модуль:' .. modAliases)
end
end
end
local alias = nil
if frameParts.mod then
if modAliases and modAliases[id] then
--- ['имя'] = '[титл]:имя[доп. текст]'
local title = mw.ustring.match ( modAliases[id], '^%[([^%]]+)%]' )
if title then
local aaa = mw.ustring.match ( modAliases[id], '^%[[^%]]+%](.+)$' )
if aaa then
alias = '[' .. title .. ']' .. frameParts.mod .. ':' .. aaa
else
alias = '[' .. title .. ']' .. frameParts.mod .. ':' .. frameParts.name
end
else
alias = frameParts.mod .. ':' .. modAliases[id]
end
end
elseif aliases and aliases[id] then
alias = aliases[id]
end
if alias then
table.insert( frames, p.expandAlias( frameParts, alias ) )
else
table.insert( frames, frame )
end
end
args[1] = table.concat( frames, ';' )
--- Построение спрайта
-- Параметры
local sprite
local ids = mw.loadData([[Модуль:ИнвСпрайт/ID]])["IDы"]
local modIds = {}
local animated = mw.ustring.find(args[1], ';')
local pageName = mw.title.getCurrentTitle().text
local imgClass = args["классизобр"]
local numStyle = args["стильцифр"]
local body = mw.html.create('span'):addClass('invslot'):css{['vertical-align'] = args["выравн"]}
if animated then
body:addClass('animated')
end
if args["класс"] then
body:addClass(args["класс"])
end
if args["стиль"] then
body:cssText(args["стиль"])
end
if (args["умолчание"] or '') ~= '' then
body:css('background-image', '{{FileUrl|' .. args["умолчание"] .. '.png}}')
end
--- Обработка фреймов
local first = true
for frame in mw.text.gsplit(args[1], '%s*;%s*') do
local item
if frame ~= '' or frame == '' and animated then
item = body:tag('span'):addClass('invslot-item')
if imgClass then
item:addClass(imgClass)
end
end
if frame == '' then
(item or body):tag('br')
else
local category
local parts = p.getParts(frame, args["мод"])
local title = parts.title or mw.text.trim(args["назв"] or '')
local mod = parts.mod
local name = parts.name
local num = parts.num
local description = parts.text
local img, idData, en_name
if mod then
local modData = modIds[mod]
if not modData and mw.title.new('Модуль:ИнвСпрайт/' .. mod .. '/ID').exists then
modData = mw.loadData('Модуль:ИнвСпрайт/' .. mod .. '/ID')["IDы"]
modIds[mod] = modData
end
if modData and modData[name] then
idData = modData[name]
en_name = idData["en"]
else
img = name .. ' (' .. mod .. ')'
end
elseif ids[name] then
idData = ids[name]
else
img = name
end
local vanilla = {v = 1, vanilla = 1, mc = 1, minecraft = 1}
local link = args["ссылка"] or ''
if link == '' then
if mod then
link = mod .. '/' .. name
else
link = nil
end
elseif mw.ustring.lower(link) == 'нет' then
link = nil
end
if link == pageName then
link = nil
end
local formattedTitle
local plainTitle
if title == '' then
plainTitle = name
elseif mw.ustring.lower(title) ~= 'нет' then
plainTitle = mw.ustring.gsub(mw.ustring.gsub(title, '\\\\', '\'), '\\&', '&')
local formatPattern = '&[0-9a-fk-or]'
if mw.ustring.match(plainTitle, formatPattern) then
formattedTitle = title
plainTitle = mw.ustring.gsub(plainTitle, formatPattern, '')
end
if plainTitle == '' then
plainTitle = name
else
plainTitle = mw.ustring.gsub(mw.ustring.gsub(plainTitle, '\', '\\'), '&', '&')
end
elseif link then
if img then
formattedTitle = ''
else
plainTitle = ''
end
end
item:attr{
['data-minetip-title'] = formattedTitle,
['data-minetip-text'] = description,
['data-modinfo-text'] = mod,
['data-minetip-lowtitle'] = en_name
}
if img then
-- & is re-escaped because mw.html treats attributes
-- as plain text, but MediaWiki doesn't
local escapedTitle = ( plainTitle or '' ):gsub( '&', '&' )
item:addClass('invslot-item-image')
:wikitext('[[Файл:Grid ', img, '.png|32x32px|link=', link or '', '|', escapedTitle, ']]')
else
if not sprite then
sprite = require([[Модуль:Спрайт]]).sprite
end
local image
if mod then
image = (args["таблспрайтов"] or mod or "Inv") .. 'CSS.png'
end
if link then
item:wikitext('[[', link, '|')
end
local image, spriteCat;
if not mod then
image, spriteCat = sprite{
["данныеID"] = idData, ["назв"] = plainTitle,
["изобр"] = image, ["настройки"] = 'ИнвСпрайт'
}
else
image, spriteCat = sprite{
["данныеID"] = idData, ["назв"] = plainTitle,
["изобр"] = image, ["настройки"] = 'ИнвСпрайт/' .. mod
}
end
item:node(image)
category = spriteCat
end
if num and num > 1 and num < 1000 then
if img and link then
item:wikitext('[[', link, '|')
end
local number = item
:tag('span')
:addClass('invslot-stacksize')
:attr{title = plainTitle}
:wikitext(num)
if numStyle then
number:cssText(numStyle)
end
if img and link then
item:wikitext(']]')
end
end
if idData and link then
item:wikitext(']]')
end
item:wikitext(category)
end
if first then
if animated and item then
item:addClass('active')
end
first = false
end
end
return tostring( body )
end
function p.expandAlias( frameParts, alias )
-- If the frame has no parts, we can just return the alias as-is
--[[if not frameParts.title and not frameParts.mod and not frameParts.num and not frameParts.text then
return alias
end--]]
local expandedFrames = {}
for aliasFrame in mw.text.gsplit(alias, '%s*;%s*') do
local aliasParts = p.getParts(aliasFrame)
aliasParts.title = frameParts.title or aliasParts.title or ''
aliasParts.mod = frameParts.mod or aliasParts.mod or 'Minecraft'
aliasParts.num = frameParts.num or aliasParts.num or ''
aliasParts.text = frameParts.text or aliasParts.text or ''
table.insert(expandedFrames, mw.ustring.format(
'[%s]%s:%s,%s[%s]',
aliasParts.title, aliasParts.mod, aliasParts.name, aliasParts.num, aliasParts.text
))
end
return table.concat(expandedFrames, ';')
end
function p.getParts(frame, mod)
----Функция получает название предмета в формате "[титл]мод:имя[доп.текст],число"
----parts.title = титл, название предмета при наведении
----parts.mod = мод
----parts.name = имя
----parts.text = текст, дополнительный текст при наведении на предмет
----parts.num = число
local parts = {}
parts.title = mw.ustring.match(frame, '^%[%s*([^%]]+)%s*%]')
local modPattern
if mw.ustring.match(frame, '^%[.*%]([a-zA-Zа-яА-Я0-9ёЁé _%-\']+):') then
modPattern = '^%[.*%]([a-zA-Zа-яА-Я0-9ёЁé _%-\']+):'
else
modPattern = '^([a-zA-Zа-яА-Я0-9ёЁé _%-\']+):'
end
parts.mod = mw.text.trim(mw.ustring.match(frame, modPattern) or mod or '') ---- Получаем название мода
local vanilla = {v = 1, vanilla = 1, mc = 1, minecraft = 1}
if parts.mod == '' or vanilla[mw.ustring.lower(parts.mod)] then
link = nil
parts.mod = nil
else
if p.modAliases[parts.mod] then
parts.mod = p.modAliases[parts.mod]
end
parts.mod = mw.ustring.gsub(parts.mod,'_',' ')
end
local _, nameStartV = mw.ustring.find( frame, '^%[[^%]]*%]' )
local nameStart = ( ({mw.ustring.find( frame, modPattern )})[2] or nameStartV or 0 ) + 1
if nameStart - 1 == #frame then
nameStart = 1
end
parts.name = mw.text.trim( mw.ustring.sub( frame, nameStart, ( mw.ustring.find( frame, '[,%[]', nameStart ) or 0 ) - 1 ) )
parts.num = math.floor(mw.ustring.match(frame, ',%s*(%d+)') or 0)
if parts.num == 0 then
parts.num = nil
end
parts.text = mw.ustring.match(frame, '%[%s*([^%]]+)%s*%]$')
return parts
end
return p