Перейти к содержимому страницы
Переключить меню
Переключить меню настроек
Переключить персональное меню
Вы не представились системе
Ваш IP-адрес будет виден всем, если вы внесёте какие-либо изменения.
Сообщество «Повелителя Тайн»Telegram — новости, дунхуа, игры и мерчDiscord — обсуждение книг и теорий, вопросы по вики

Модуль:Pathways: различия между версиями

Материал из проекта «Повелитель Тайн Вики»
imported>Import
Импорт с англ. вики (CC BY-SA)
imported>Import
Импорт с англ. вики (CC BY-SA)
 
(не показано 12 промежуточных версий 2 участников)
Строка 8: Строка 8:
-- [ru] "Путь X" forms for pathways referenced by their Sequence 9 (or other) names.
-- [ru] "Путь X" forms for pathways referenced by their Sequence 9 (or other) names.
local SEQ_PATHWAY_RU = {
local SEQ_PATHWAY_RU = {
     ["Seer"] = "Путь Провидца", ["Apprentice"] = "Путь Ученика", ["Marauder"] = "Путь Мародера",
     ["Seer"] = "Путь Провидца", ["Apprentice"] = "Путь Ученика", ["Marauder"] = "Путь Мародёра",
     ["Spectator"] = "Путь Зрителя", ["Bard"] = "Путь Барда", ["Sailor"] = "Путь Моряка",
     ["Spectator"] = "Путь Зрителя", ["Bard"] = "Путь Барда", ["Sailor"] = "Путь Моряка",
     ["Reader"] = "Путь Читателя", ["Secrets Suppliant"] = "Путь Жреца Тайн", ["Sleepless"] = "Путь Бессонного",
     ["Reader"] = "Путь Читателя", ["Secrets Suppliant"] = "Путь Просителя Секретов", ["Sleepless"] = "Путь Бессонного",
     ["Corpse Collector"] = "Путь Сборщика Трупов", ["Warrior"] = "Путь Воина", ["Assassin"] = "Путь Ассасина",
     ["Corpse Collector"] = "Путь Собирателя трупов", ["Warrior"] = "Путь Воина", ["Assassin"] = "Путь Ассасина",
     ["Hunter"] = "Путь Охотника", ["Mystery Pryer"] = "Путь Искателя Тайн", ["Savant"] = "Путь Саванта",
     ["Hunter"] = "Путь Охотника", ["Mystery Pryer"] = "Путь Жреца Тайн", ["Savant"] = "Путь Эрудита",
     ["Monster"] = "Путь Монстра", ["Planter"] = "Путь Плантатора", ["Apothecary"] = "Путь Аптекаря",
     ["Monster"] = "Путь Монстра", ["Planter"] = "Путь Плантатора", ["Apothecary"] = "Путь Аптекаря",
     ["Criminal"] = "Путь Преступника", ["Prisoner"] = "Путь Заключенного", ["Lawyer"] = "Путь Адвоката",
     ["Criminal"] = "Путь Преступника", ["Prisoner"] = "Путь Заключенного", ["Lawyer"] = "Путь Адвоката",
Строка 95: Строка 95:
     local pathwayName = name
     local pathwayName = name
     local img = 'Baboon Icon.png'
     local img = 'Baboon Icon.png'
     local link = "Unknown"
     local link = "Пути" -- [ru] было "Unknown" (несуществующая страница)


     local is_patwhway
     local is_patwhway
Строка 393: Строка 393:
         icon = ''
         icon = ''
     end
     end
     local link_text = string.format('[[Uniquenesses#%s|%s]]', pathway_data["name_ru_full"] or link, display_text)
     local link_text = string.format('[[Уникальности#%s|%s]]', pathway_data["name_ru_full"] or link, display_text)


     return icon .. link_text
     return icon .. link_text
Строка 446: Строка 446:


     return tostring(cardTable)
     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
-- [ru] link to a section only if the target page actually has it (non-standard pathways
-- often have no per-Sequence sections on their /Advancement or /Abilities pages)
local _pageTextCache = {}
local function pageText(page)
    local c = _pageTextCache[page]
    if c ~= nil then return c end
    c = false
    local t = mw.title.new(page)
    local hops = 0
    while t and hops < 3 do
        local txt = t:getContent()
        if not txt then break end
        local tgt = mw.ustring.match(txt, '^%s*#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt]%s*%[%[([^%]#|]+)')
            or mw.ustring.match(txt, '^%s*#ПЕРЕНАПРАВЛЕНИЕ%s*%[%[([^%]#|]+)')
        if tgt then
            t = mw.title.new(mw.text.trim(tgt)); hops = hops + 1
        else
            c = txt; break
        end
    end
    _pageTextCache[page] = c
    return c
end
local function sectionTarget(page, anchor)
    if not anchor or anchor == '' then return page end
    local txt = pageText(page)
    if txt and string.find(txt, anchor, 1, true) then
        return page .. '#' .. anchor
    end
    return page
end
end


Строка 493: Строка 555:
     headerRowSequence:attr('width', '20%')
     headerRowSequence:attr('width', '20%')
                     :css('background', colourAltHeading)
                     :css('background', colourAltHeading)
                     :wikitext('Последовательность')
                     :wikitext('Посл.')
     local headerRowName = headerRow:tag('th')
     local headerRowName = headerRow:tag('th')
     headerRowName:css('background', colourAltHeading)
     headerRowName:css('background', colourAltHeading)
Строка 532: Строка 594:
         local set_link = string.format(
         local set_link = string.format(
             '<div style="font-style: italic; font-size: 11px; padding: 0px; margin: 0px;">' ..  
             '<div style="font-style: italic; font-size: 11px; padding: 0px; margin: 0px;">' ..  
                 '<div style="text-align: left;">[[%s/Abilities#%s|Спос.]]</div>' ..  
                 '<div style="text-align: left;">[[%s|Спос.]]</div>' ..  
                 '<div style="color: gray; margin: -18px -2px; user-select: none; text-align: center; font-size: 16px;"><center>/</center></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 style="text-align: right;">[[%s|Прод.]]</div>' ..
             '</div>',
             '</div>',
             seq_data["pathway"], seq_data["link"],
             sectionTarget(seq_data["pathway"] .. '/Abilities', seq_data["link"]),
             seq_data["pathway"], seq_data["link"]
             sectionTarget(seq_data["pathway"] .. '/Advancement', seq_data["link"])
         )
         )



Текущая версия от 16:30, 1 ноября 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 = "&nbsp; &bull; &nbsp;"

-- [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 = "Пути" -- [ru] было "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 ('&nbsp;' .. 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 ('&nbsp;' .. 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('[[Уникальности#%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

-- [ru] link to a section only if the target page actually has it (non-standard pathways
-- often have no per-Sequence sections on their /Advancement or /Abilities pages)
local _pageTextCache = {}
local function pageText(page)
    local c = _pageTextCache[page]
    if c ~= nil then return c end
    c = false
    local t = mw.title.new(page)
    local hops = 0
    while t and hops < 3 do
        local txt = t:getContent()
        if not txt then break end
        local tgt = mw.ustring.match(txt, '^%s*#[Rr][Ee][Dd][Ii][Rr][Ee][Cc][Tt]%s*%[%[([^%]#|]+)')
            or mw.ustring.match(txt, '^%s*#ПЕРЕНАПРАВЛЕНИЕ%s*%[%[([^%]#|]+)')
        if tgt then
            t = mw.title.new(mw.text.trim(tgt)); hops = hops + 1
        else
            c = txt; break
        end
    end
    _pageTextCache[page] = c
    return c
end

local function sectionTarget(page, anchor)
    if not anchor or anchor == '' then return page end
    local txt = pageText(page)
    if txt and string.find(txt, anchor, 1, true) then
        return page .. '#' .. anchor
    end
    return page
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|Спос.]]</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|Прод.]]</div>' ..
            '</div>',
            sectionTarget(seq_data["pathway"] .. '/Abilities', seq_data["link"]),
            sectionTarget(seq_data["pathway"] .. '/Advancement', 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