Модуль:Pathways: различия между версиями
Материал из проекта «Повелитель Тайн Вики»
Дополнительные действия
imported>Import Импорт с англ. вики (CC BY-SA) |
imported>Import Импорт с англ. вики (CC BY-SA) |
(нет различий)
| |
Версия от 21:00, 31 октября 2026
General
The module to use with {{Pathway}} and {{Uniqueness}} templates.
To add more data for the sequence, go to Module:Sequence/pathways and Module:Sequence/ATS.
Sample
Шут
Уникальность Шута
Повелитель Тайн
Мать-Богиня Разврата
local p = {}
local seq_helpers = require("Module:Sequence/Helpers")
local helpers = require("Module:Helpers")
local separator = " • "
-- [ru] "Путь X" forms for pathways referenced by their Sequence 9 (or other) names.
local SEQ_PATHWAY_RU = {
["Seer"] = "Путь Провидца", ["Apprentice"] = "Путь Ученика", ["Marauder"] = "Путь Мародера",
["Spectator"] = "Путь Зрителя", ["Bard"] = "Путь Барда", ["Sailor"] = "Путь Моряка",
["Reader"] = "Путь Читателя", ["Secrets Suppliant"] = "Путь Жреца Тайн", ["Sleepless"] = "Путь Бессонного",
["Corpse Collector"] = "Путь Сборщика Трупов", ["Warrior"] = "Путь Воина", ["Assassin"] = "Путь Ассасина",
["Hunter"] = "Путь Охотника", ["Mystery Pryer"] = "Путь Искателя Тайн", ["Savant"] = "Путь Саванта",
["Monster"] = "Путь Монстра", ["Planter"] = "Путь Плантатора", ["Apothecary"] = "Путь Аптекаря",
["Criminal"] = "Путь Преступника", ["Prisoner"] = "Путь Заключенного", ["Lawyer"] = "Путь Адвоката",
["Arbiter"] = "Путь Арбитра",
}
local SEQ_PATHWAY_RU_LOWER = {}
for k, v in pairs(SEQ_PATHWAY_RU) do SEQ_PATHWAY_RU_LOWER[string.lower(k)] = v end
local NO_DATA = '<span style="color: gray">-- Нет данных --</span>'
local DELIM = ";;"
local EQUAL = "::"
function distributeSymmetric(n)
local size = math.ceil(math.sqrt(n))
if n == 1 then
return { 1 }, 1
end
if n == 3 then
return { 1, 2 }, size
end
local rows = {}
-- 1. Initialize with the floor value
local baseValue = math.floor(n / size)
local extra = n % size
for i = 1, size do
rows[i] = baseValue
end
-- 2. Distribute extras from the outside-in
-- This ensures the "heavy" parts are at the ends (top/bottom)
-- or if extra is 1, it hits the center.
local left = 1
local right = size
while extra > 0 do
if left == right then
rows[left] = rows[left] + extra
extra = 0
else
rows[left] = rows[left] + 1
rows[right] = rows[right] + 1
extra = extra - 2
left = left + 1
right = right - 1
end
end
return rows, size
end
function contains(str, substring)
if str == nil then return false end
return string.find(str, substring) ~= nil
end
function generateIcon(img, iconsize, link)
return string.format('[[File:%s|%s|link=%s]]', img, iconsize, link)
end
function isNilOrWhitespace(str)
if str == nil then return true end
if #str == 0 then return true end
return str:match("^%s*$") ~= nil
end
function p.pathwayLink(frame, name, add_p, label, note, iconsize, mode)
if name == nil or name == "" then
return
end
if name == "Unknown" then
return "''Неизвестный Путь''"
end
if iconsize == nil or #iconsize == 0 then iconsize = '26px' end
local pathwayName = name
local img = 'Baboon Icon.png'
local link = "Unknown"
local is_patwhway
local display_name_full -- [ru] "Путь X" form used when add_p is set
local data
local display_name = name
local data_name = name
local seq_data = seq_helpers.findSequence(name)
if seq_data ~= nil then
pathway_data = seq_helpers.findPathway(seq_data["pathway"])
end
local pathway_data = pathway_data or seq_helpers.findPathway(name)
if pathway_data ~= nil then
is_patwhway = true
img = pathway_data['file'] or img
link = pathway_data['link'] or link
data = pathway_data
if seq_data ~= nil then
display_name = seq_data["name_ru"] or seq_data["@key_to_alt_name"][name] or display_name
display_name_full = SEQ_PATHWAY_RU_LOWER[string.lower(helpers.trimWhitespace(name))] or pathway_data["name_ru_full"]
else
display_name = pathway_data["name_ru"] or pathway_data["@name_id"] or display_name
display_name_full = pathway_data["name_ru_full"]
end
data_name = pathway_data["@name_id"] or data_name
end
if data == nil then
data = seq_helpers.findAts(name)
if data ~= nil then
img = data['file'] or img
link = data['link'] or link
data_name = data['ats_title'] or data_name
display_name = data['ats_title_ru'] or data['ats_title'] or display_name
end
end
if add_p then
display_name = display_name_full or ("Путь " .. display_name)
end
if label ~= nil and #label > 0 then
display_name = label
end
local icon = contains(mode, "noicon") and '' or generateIcon(img, iconsize, link)
local main_text = (contains(mode, "nolink") and '') or
(contains(mode, "nohref") and string.format('%s', display_name)) or
string.format('[[%s|%s]]', link, display_name)
if contains(mode, "center") or contains(mode, "centre") then
local tooltipSpan = mw.html.create('span')
:attr('class', 'pathway-tooltip')
:attr('data-pathway', data_name)
:wikitext(icon)
:tag('br')
:done()
:wikitext(main_text .. ((not isNilOrWhitespace(note)) and (' ' .. note) or ''))
return string.format('<center>%s</center>', tostring(tooltipSpan))
else
local tooltipSpan = mw.html.create('span')
:attr('class', 'pathway-tooltip')
:attr('data-pathway', data_name)
:wikitext(icon .. ((not isNilOrWhitespace(main_text)) and (' ' .. main_text) or ''))
:wikitext((not isNilOrWhitespace(note)) and (' ' .. note) or '')
return tostring(tooltipSpan)
end
end
function cleanString(str)
if str == nil then return nil end
str = helpers.trimWhitespace(str)
if #str == 0 then return nil end
return str
end
function p.pathwayLinkInvokable(frame)
local args = frame.args
local name = args[1]
local label = args["label"]
local note = args["note"]
local add_p1 = cleanString(args["pathway"]) or cleanString(args["p"]) or cleanString(args["path"])
local iconsize1 = cleanString(args["iconsize"])
local mode1 = cleanString(args["mode"])
local add_p2 = cleanString(args["pathway2"])
local iconsize2 = cleanString(args["iconsize2"])
local mode2 = cleanString(args["mode2"])
local add_p = helpers.strToBool(helpers.ternary(add_p1 ~= nil, add_p1, add_p2))
local iconsize = iconsize1 or iconsize2
local mode = mode1 or mode2
return p.pathwayLink(frame, name, add_p, label, note, iconsize, mode)
end
function p.pathwayLinkMultInvokable(frame)
local args = frame.args
local output = {}
local mode = cleanString(args['mode'])
local iconsize = cleanString(args['iconsize'])
local add_p = helpers.strToBool(args["pathway"] or args["p"] or args["path"])
local sep = cleanString(args['separator'])
-- Squared disables the text.
if contains(mode, "squared") then
mode = mode .. ";nolink"
end
for i, argument in ipairs(args) do
if argument ~= "" then
local note = args[argument .. "_note"]
if note == nil or #note == 0 then note = nil end
local replaced = argument:gsub(DELIM, "|")
local replaced = replaced:gsub(EQUAL, "=")
local retemplate = string.format(
"{{Pathway/one%s|%s%s%s%s}}",
(note ~= nil) and ("|note=" .. note) or "",
replaced,
(mode ~= nil) and ("|mode2=" .. mode) or "",
(iconsize ~= nil) and ("|iconsize2=" .. iconsize) or "",
((add_p == true) and ("|pathway2=true")) or ""
)
local result = frame:preprocess(retemplate)
table.insert(output, result)
end
end
if contains(mode, "squared") then
local span_width = 26
if iconsize ~= nil then
span_width = tonumber(iconsize:match("%d+"))
end
local n = #output
local rows
local size_base
rows, size_base = distributeSymmetric(n)
local size = span_width * size_base
local i = 0
local html = {}
local empty_div = '<div style="flex:1;"></div>'
if n ~= 2 then
for q, row_count in ipairs(rows) do
local row_items = {}
local is_even_diff = (size_base - row_count) % 2 == 0
local exact = size_base == row_count
for j = 1, row_count do
if is_even_diff and not exact then
table.insert(row_items, empty_div)
end
i = i + 1
local content = output[i]
local ind_str = string.format('<div style="flex:1; text-align:center;">%s</div>', content)
table.insert(row_items, ind_str)
if (not is_even_diff) and j < row_count and not exact then
table.insert(row_items, empty_div)
end
end
if is_even_diff and not exact then
table.insert(row_items, empty_div)
end
local row_div = string.format('<div style="display:flex; width:100%%; height:%dpx;">', span_width) ..
table.concat(row_items) ..
'</div>'
table.insert(html, row_div)
end
else
local str_1 = string.format('<div style="display:flex; width:100%%; height:%dpx; text-align:left;">%s</div>', span_width, output[1])
table.insert(html, str_1)
local str_2 = string.format('<div style="display:flex; width:100%%; height:%dpx;">%s<div style="flex:1; text-align:center;">%s</div></div>', span_width, empty_div, output[2])
table.insert(html, str_2)
end
return string.format('<div style="width:%dpx; height:%dpx; display:flex; flex-direction:column; justify-content: center; margin: auto">', size, size) ..
table.concat(html) ..
"</div>"
end
if sep ~= nil then
return table.concat(output, sep)
end
if contains(mode, "inline") then
return table.concat(output, separator)
end
return table.concat(output, '<br>')
end
function p.pathwayCard(frame)
local name_arg = frame.args[1]
local pathway_data = seq_helpers.findPathway(name_arg)
local ats_data = seq_helpers.findAts(name_arg)
local data = pathway_data or ats_data
if pathway_data == nil and ats_data == nil then
if string.lower(name_arg) == 'unknown' then
return "Неизвестно"
end
return name_arg
end
local color = '#FFF'
local display_name = name_arg
local file = 'Baboon Icon.png'
local description = ""
if pathway_data ~= nil then
file = pathway_data['file'] or file
display_name = seq_helpers.pathwayDisplayName(pathway_data)
description = pathway_data.description_ru or pathway_data.description or description
local ats_belonged = seq_helpers.atsGroupOf(pathway_data["@name_id"])
if ats_belonged ~= nil then
color = ats_belonged['color'] or color
end
elseif ats_data ~= nil then
color = ats_data['color'] or color
display_name = data["ats_title_ru"] or data["ats_title"] or display_name
file = ats_data['file'] or file
if ats_data.ats_group ~= nil then
description = frame:preprocess(string.format('{{Pathway/group|%s|16px|dropdown=no}}', ats_data.ats_group))
end
end
-- Construct card HTML
local cardTable = mw.html.create('table')
cardTable:css('background-color', 'transparent')
:css('width', '300px')
-- Add rows to the table
local row1 = cardTable:tag('tr')
row1:tag('td')
:css('width', '60px')
:attr('rowspan', '2')
:wikitext(string.format('[[File:%s|60px]]', file))
row1:tag('td')
:css('text-transform', 'uppercase')
:css('font-weight', 'bold')
:css('color', color)
:css('font-size', 'larger')
:wikitext(display_name)
local row2 = cardTable:tag('tr')
row2:tag('td')
:attr('colspan', '2')
:css('color', 'gray')
:wikitext(description)
return tostring(cardTable)
end
-- New function: p.uniqueness
function p.uniquenessLink(frame)
local args = frame.args
local name = args[1]
local custom_label = args[2]
local mode = cleanString(args['mode'])
if not name or name == '' then
return NO_DATA
end
local pathway_data = seq_helpers.findPathway(name) or {}
local img = pathway_data['file']
local link = pathway_data['link'] or name
local default_text = pathway_data["name_ru_gen"] and ('Уникальность ' .. pathway_data["name_ru_gen"]) or ((pathway_data["@name_id"] or name ) .. ' Uniqueness')
local display_text = (custom_label and custom_label ~= '') and custom_label or default_text
local icon = (img and img ~= '') and string.format('[[File:%s|26px|link=%s]] ', img, link) or ''
if contains(mode, "noicon") then
icon = ''
end
local link_text = string.format('[[Uniquenesses#%s|%s]]', pathway_data["name_ru_full"] or link, display_text)
return icon .. link_text
end
function missingPathway(key)
if string.lower(key) == 'unknown' then
return NO_DATA
end
return string.format('<span style="color: red">-- Неверное название «%s» --</span>', key)
end
function p.uniquenessCard(frame)
local name_arg = frame.args[1]
local pathway_data = seq_helpers.findPathway(name_arg)
-- Handle missing or unknown data
if not pathway_data then
return missingPathway(key)
end
local color = '#FFF'
local iconFile = pathway_data['file'] or 'Baboon Icon.png'
local displayName = pathway_data["name_ru_gen"] and ('Уникальность ' .. pathway_data["name_ru_gen"]) or (pathway_data["@name_id"] .. ' Uniqueness')
local ats_belonged = seq_helpers.atsGroupOf(pathway_data["@name_id"])
if ats_belonged ~= nil then
color = ats_belonged['color'] or color
end
-- Build card table
local cardTable = mw.html.create('table')
cardTable:css('background-color', 'transparent')
:css('width', '300px')
-- First row: icon and label
local row1 = cardTable:tag('tr')
row1:tag('td')
:css('width', '60px')
:attr('rowspan', '2')
:wikitext(string.format('[[File:%s|60px]]', iconFile))
row1:tag('td')
:css('text-transform', 'uppercase')
:css('font-weight', 'bold')
:css('color', color)
:css('font-size', 'larger')
:wikitext(displayName)
return tostring(cardTable)
end
-- [ru] Russian name of a pathway for use in templates:
-- {{#invoke:Pathways|ruName|Fool}} -> "Путь Шута"; form=short -> "Шут"; form=gen -> "Шута"
function p.ruName(frame)
local name = helpers.trimWhitespace(frame.args[1] or '')
local form = frame.args['form'] or 'full'
local data = seq_helpers.findPathway(name)
if data == nil then
local ats = seq_helpers.findAts(name)
if ats ~= nil then return ats['ats_title_ru'] or ats['ats_title'] end
if form == 'full' then return name .. ' Pathway' end
return name
end
if form == 'short' then return data['name_ru'] or data['@name_id'] end
if form == 'gen' then return data['name_ru_gen'] or data['@name_id'] end
return data['name_ru_full'] or (data['@name_id'] .. ' Pathway')
end
-- [ru] Russian name of a sequence: {{#invoke:Pathways|ruSeq|Seer}} -> "Провидец"
function p.ruSeq(frame)
local name = helpers.trimWhitespace(frame.args[1] or '')
local data = seq_helpers.findSequence(name)
if data == nil then
local ats = seq_helpers.findAts(name)
if ats ~= nil then return ats['ats_title_ru'] or ats['ats_title'] end
return name
end
return data['name_ru'] or name
end
function p.pathwaySequenceNames(frame)
local name_arg = frame.args[1]
local equal_names = helpers.strToBool(frame.args["equal_names"])
local pathway_data = seq_helpers.findPathway(name_arg)
-- Handle missing or unknown data
if not pathway_data then
return missingPathway(key)
end
local color = '#FFF'
local colourWhite = "#FFF"
local colourHeading = '#3f3f3f'
local colourAltHeading = '#3f3f3f4D'
local ats_belonged = seq_helpers.atsGroupOf(pathway_data["@name_id"])
if ats_belonged ~= nil then
color = ats_belonged['color'] or color
end
local seqTable = mw.html.create('table')
seqTable:css('max-width', '550px')
:css('width', '45%')
:css('text-align', 'center')
:css('border', '1px solid ' .. color)
:css('font-size', '90%')
local indexRow = seqTable:tag('tr')
local indexTDH = indexRow:tag('th')
indexTDH:attr('colspan', '2')
:css('background', colourHeading)
:css('color', colourWhite)
:wikitext(seq_helpers.pathwayDisplayName(pathway_data) .. ": Последовательности")
local indexIcon = indexRow:tag('th')
indexIcon:attr('rowspan', '2')
:css('background', colourAltHeading)
if pathway_data['file'] then
indexIcon:wikitext(frame:preprocess(string.format("[[File:%s|45px]]", pathway_data['file'])))
end
local headerRow = seqTable:tag('tr')
local headerRowSequence = headerRow:tag('th')
headerRowSequence:attr('width', '20%')
:css('background', colourAltHeading)
:wikitext('Посл.')
local headerRowName = headerRow:tag('th')
headerRowName:css('background', colourAltHeading)
:css('width', '80%')
:wikitext('Название')
for i, seq_data in ipairs(seq_helpers.sequenceListData(name_arg)) do
local function throughSequenceHeading(label)
local headerThroughSequence = seqTable:tag('tr')
headerThroughSequence:css('background', colourAltHeading)
:css('color', colourWhite)
headerThroughSequence:tag('th')
headerThroughSequence:tag('th'):wikitext(frame:preprocess(label))
headerThroughSequence:tag('th')
end
if i == 1 then -- 1, 2, 3 => Seq 9, 8
throughSequenceHeading('{{Language|Низкие Последовательности|低序列|Simplified Chinese|4}}')
elseif i == 3 then -- 4, 5 => Seq 7, 6, 5
throughSequenceHeading('{{Language|Средние Последовательности|中序列|Simplified Chinese|4}}')
elseif i == 6 then -- 6, 7 => Seq 4, 3
throughSequenceHeading('{{Language|Высокие Последовательности|高序列|Simplified Chinese|4}} — {{Language|Святой|圣者|Simplified Chinese|4}}')
elseif i == 8 then -- 8, 9 => Seq 2, 1
throughSequenceHeading('{{Language|Высокие Последовательности|高序列|Simplified Chinese|4}} — {{Language|Ангел|天使|Simplified Chinese|4}}')
elseif i == 10 then -- 10 => 0
throughSequenceHeading('{{Language|Истинный Бог|真神|Simplified Chinese|4}}')
end
local name_infos = seq_helpers.dataNameInfos(seq_data, false)
-- [ru] primary name shown in Russian, English kept in the popup
if seq_data["name_ru"] ~= nil and name_infos[1] ~= nil then
name_infos[1]['name_en'] = name_infos[1]['name']
name_infos[1]['name'] = seq_data["name_ru"]
end
local seq_name = ""
local set_link = string.format(
'<div style="font-style: italic; font-size: 11px; padding: 0px; margin: 0px;">' ..
'<div style="text-align: left;">[[%s/Abilities#%s|Спос.]]</div>' ..
'<div style="color: gray; margin: -18px -2px; user-select: none; text-align: center; font-size: 16px;"><center>/</center></div>' ..
'<div style="text-align: right;">[[%s/Advancement#%s|Прод.]]</div>' ..
'</div>',
seq_data["pathway"], seq_data["link"],
seq_data["pathway"], seq_data["link"]
)
local first_info = name_infos[1]
if #name_infos > 1 or first_info['flag'] or first_info['cn'] or first_info['romanised'] or first_info['name_en'] then
local string_builder = {}
local names_set = {}
local data_properties = require("Module:Sequence/DataProperties")
for i, curr in ipairs(name_infos) do
local flag = curr['flag']
-- Flag can be nil.
if flag == nil then
flag = false
end
if names_set[flag] == nil then
names_set[flag] = {}
end
table.insert(names_set[flag], curr)
end
local function namesFormatter(curr_set)
local substr = ""
local flag = curr_set[1]['flag']
if flag ~= nil then
substr = string.format('<div>%s:</div>', flag)
end
local sub_names = {}
for _, n in ipairs(curr_set) do
local value = '<span style="user-select: none;">- </span>' .. n['name'] .. (n['name_en'] and (' <span style="color: gray;">(' .. n['name_en'] .. ')</span>') or '') .. (n['ref'] or '')
if n['cn'] or n['romanised'] then
value = value .. '<br/><span style="opacity: 0.0; user-select: none;">- </span>' ..
(n['cn'] or '<span style="color: red; font-style: italic;">НЕТ КИТ. НАЗВАНИЯ</span>') ..
(n['romanised'] and (': ' .. n['romanised']) or '')
end
table.insert(sub_names, value )
end
substr = substr ..
'<ul style="margin: 0 0 0 0;"> <li>' ..
table.concat( sub_names, "</li> <li>" ) ..
'</li> </ul>'
return string.format('<div style="padding: 5px 0px">%s</div>', substr)
end
-- Starting with the flag that's nil.
if names_set[false] then
table.insert(
string_builder,
namesFormatter(names_set[false])
)
end
for key, curr_names in pairs(names_set) do
if key ~= false then
table.insert(
string_builder,
namesFormatter(curr_names)
)
end
end
if #name_infos == 1 then
seq_name = string.format([=[{{Popup|text = <span style="text-decoration:underline dotted; cursor:help;">%s</span>|popup = <span class="mobile-hidden">%s</span>|inline = 1}}]=],
name_infos[1]['name'],
table.concat( string_builder, "" )
)
else
seq_name = string.format(
"{{Popup|text = " ..
[=[<span style="text-decoration:underline dotted; cursor:help;">%s</span>]=] ..
[=[<sub><span class="nomobile" style="color: rgba(140, 140, 140, 0.4);">[%d]</span></sub>]=] ..
"|popup = " ..
[=[<span class="mobile-hidden">%s</span>]=] ..
"|inline = 1}}",
name_infos[1]['name'],
#name_infos,
table.concat( string_builder, "" )
)
end
else
seq_name = name_infos[1]['name']
end
local name_list = '<div style="padding: 0px;">' ..
seq_name ..
"</div>"
local dataRow = seqTable:tag('tr')
dataRow:tag('td')
:css('font-size', "12.4px")
:wikitext(tostring(10 - i))
dataRow:tag('td')
:css('padding', "6px 2px")
:wikitext(frame:preprocess(name_list))
dataRow:tag('td')
:wikitext(set_link)
end
return tostring(seqTable)
end
return p