Модуль:Автоматическая статистика: различия между версиями
Перейти к навигации
Перейти к поиску
Восстановлена версия 69713 участника Дача Цанавы (Restorer) Метка: отмена |
Lord (обсуждение | вклад) Нет описания правки |
||
| (не показаны 4 промежуточные версии 2 участников) | |||
| Строка 1: | Строка 1: | ||
-- ========================================== | -- ========================================== | ||
-- Модуль:Автоматическая статистика | -- Модуль:Автоматическая статистика | ||
-- (Pure UI Render для PlayerStats) | -- (Pure UI Render для PlayerStats JSON) | ||
-- ========================================== | -- ========================================== | ||
| Строка 132: | Строка 132: | ||
td:cssText(style .. Config.styles.header) | td:cssText(style .. Config.styles.header) | ||
else | else | ||
local m_data = compiled_data.metrics[row.id].years[year] | local m_data = compiled_data.metrics[row.id] and compiled_data.metrics[row.id].years[year] or { val=0, num=0, den=0, color="" } | ||
if m_data.color ~= "" then style = style .. m_data.color end | if m_data.color and m_data.color ~= "" then style = style .. m_data.color end | ||
td:cssText(style) | td:cssText(style) | ||
| Строка 154: | Строка 154: | ||
td_tot:cssText(style_tot):wikitext("—") | td_tot:cssText(style_tot):wikitext("—") | ||
else | else | ||
local m_tot = compiled_data.metrics[row.id] | local m_tot = compiled_data.metrics[row.id] or { total_val=0, total_num=0, total_den=0, color="" } | ||
if m_tot.color and m_tot.color ~= "" then style_tot = style_tot .. m_tot.color end | if m_tot.color and m_tot.color ~= "" then style_tot = style_tot .. m_tot.color end | ||
td_tot:cssText(style_tot) | td_tot:cssText(style_tot) | ||
| Строка 171: | Строка 171: | ||
end | end | ||
if show_matches and | if show_matches and compiled_data.player_matches_list then | ||
local pml = compiled_data.player_matches_list | -- 1. СНАЧАЛА копируем Read-Only прокси-массив в чистую Lua-таблицу | ||
-- ipairs работает с JSON-прокси безупречно | |||
local pml = {} | |||
for _, m in ipairs(compiled_data.player_matches_list) do | |||
table.insert(pml, m) | |||
end | |||
local url_matches = "https://thirdworldcup.ru/index.php?title=%D0%9F%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0:%D0%A0%D0%B0%D0%B7%D0%B2%D1%91%D1%80%D1%82%D0%BA%D0%B0_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BC%D0%B0%D1%82%D1%87%D0%B5%D0%B9&action=edit" | -- 2. ТЕПЕРЬ проверяем длину чистого массива pml, а не сломанного JSON-объекта | ||
if #pml > 0 then | |||
table.sort(pml, function(a, b) return a.num_hist < b.num_hist end) | |||
local url_matches = "https://thirdworldcup.ru/index.php?title=%D0%9F%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0:%D0%A0%D0%B0%D0%B7%D0%B2%D1%91%D1%80%D1%82%D0%BA%D0%B0_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BC%D0%B0%D1%82%D1%87%D0%B5%D0%B9&action=edit" | |||
local match_gear = " [[Файл:Gear icon.svg|12px|link=" .. url_matches .. "]] " | |||
local list_classes = 'wikitable mw-collapsible' | |||
if show_main then list_classes = list_classes .. ' mw-collapsed' end | |||
local t_list = mw.html.create('table'):addClass(list_classes) | |||
t_list:tag('tr'):tag('th'):attr('colspan', '9'):wikitext((compiled_data.played_before_2022 and "Полный список матчей начиная с ЧТМ-2022" or "Полный список матчей") .. match_gear) | |||
local h_tr = t_list:tag('tr') | |||
local cols = {"№", "Настоящая<br>дата", "ЧТМ<br>(№ матча)", "Раунд", "Команда", "Соперник", "Счёт", "Статистика", "Дополнительно"} | |||
for _, col in ipairs(cols) do h_tr:tag('th'):attr('scope', 'col'):cssText(Config.styles.header):wikitext(col) end | |||
local counter = 1 | |||
for _, m in ipairs(pml) do | |||
local tr = t_list:tag('tr') | |||
local bg_color = get_match_color(m) | |||
local style_td = "white-space:nowrap;text-align:center;" .. (bg_color ~= "" and ("background-color:" .. bg_color .. ";") or "") | |||
tr:tag('td'):cssText(style_td):wikitext(m.is_official and tostring(counter) or ""); if m.is_official then counter = counter + 1 end | |||
tr:tag('td'):cssText(style_td):wikitext(m.is_official and (m.date ~= "" and (m.date:sub(9,10).."."..m.date:sub(6,7).."."..m.date:sub(1,4)) or "") or "") | |||
tr:tag('td'):cssText(style_td):wikitext("[[" .. m.year .. "]] (" .. m.match_num_id .. ")") | |||
tr:tag('td'):cssText(style_td):wikitext(format_stage(m.stage, m.letter)) | |||
local score_txt = format_score(m); if m.wikilink then score_txt = "'''[[" .. m.wikilink .. "|" .. score_txt .. "]]'''" end | |||
if m.role_team == 0 then | |||
tr:tag('td'):attr('colspan', '3'):cssText(style_td):wikitext("Вратарь ([[" .. Teams.getName(m.team1, 'short') .. "]] - [[" .. Teams.getName(m.team2, 'short') .. "]] - " .. score_txt .. ")") | |||
else | |||
tr:tag('td'):cssText(style_td):wikitext("[[" .. Teams.getName((m.role_team == 1) and m.team1 or m.team2, 'short') .. "]]") | |||
tr:tag('td'):cssText(style_td):wikitext("[[" .. Teams.getName((m.role_team == 1) and m.team2 or m.team1, 'short') .. "]]") | |||
tr:tag('td'):cssText(style_td):wikitext(score_txt) | |||
end | |||
local s_arr = {} | |||
if m.goals > 0 then table.insert(s_arr, "'''" .. (m.goals > 1 and m.goals or "") .. "Г'''") end | |||
if m.assists > 0 then table.insert(s_arr, "'''" .. (m.assists > 1 and m.assists or "") .. "П'''") end | |||
tr:tag('td'):cssText(style_td):wikitext(" | if m.is_mvp then table.insert(s_arr, "'''<u>MVP</u>'''") end | ||
tr:tag('td'):cssText(style_td):wikitext(" | tr:tag('td'):cssText(style_td):wikitext(table.concat(s_arr, ", ")) | ||
-- 3. РАСПАКОВЫВАЕМ m.events, чтобы корректно работали оператор длины (#) и table.concat | |||
local safe_events = {} | |||
if m.events then | |||
for _, ev in ipairs(m.events) do table.insert(safe_events, ev) end | |||
end | |||
tr:tag('td'):cssText(style_td):wikitext(#safe_events > 0 and ("<small>" .. table.concat(safe_events, "<br>") .. "</small>") or "<small></small>") | |||
end | end | ||
html_list = tostring(t_list) | |||
end | end | ||
end | end | ||
| Строка 220: | Строка 239: | ||
local show_nav = { | local show_nav = { | ||
champs = (N.champ_counts[player_name] or 0) > 0, superchamps = false, zshar = false, zbashmak = false, elnur = false, | champs = (N.champ_counts and N.champ_counts[player_name] or 0) > 0, superchamps = false, zshar = false, zbashmak = false, elnur = false, | ||
final_goals = (N.final_goals[player_name] or 0) > 0, final_assists = (N.final_assists[player_name] or 0) > 0, | final_goals = (N.final_goals and N.final_goals[player_name] or 0) > 0, final_assists = (N.final_assists and N.final_assists[player_name] or 0) > 0, | ||
club100 = (N.global_goals[player_name] or 0) >= 100, loyalty = false, | club100 = (N.global_goals and N.global_goals[player_name] or 0) >= 100, loyalty = false, | ||
org = (player_name == "Диман" or player_name == "Антон" or player_name == "Геныч") | org = (player_name == "Диман" or player_name == "Антон" or player_name == "Геныч") | ||
} | } | ||
| Строка 231: | Строка 250: | ||
local icon_td = args.noIcon and '<td style="vertical-align:middle; text-align:left; padding:0; display:none;"></td>' | local icon_td = args.noIcon and '<td style="vertical-align:middle; text-align:left; padding:0; display:none;"></td>' | ||
or string.format('<td style="vertical-align:middle; text-align:left; padding:0; width:%s;">%s</td>', args.iconW or '30px', args.icon) | or string.format('<td style="vertical-align:middle; text-align:left; padding:0; width:%s;">%s</td>', args.iconW or '30px', args.icon) | ||
local full_edit = mw.uri.encode("Шаблон:" .. args.editName, "PATH") | local full_edit = mw.uri.encode("Шаблон:" .. args.editName, "PATH") | ||
local url_edit = "https://thirdworldcup.ru/index.php?title=" .. full_edit .. "&action=edit" | local url_edit = "https://thirdworldcup.ru/index.php?title=" .. full_edit .. "&action=edit" | ||
local url_view = "https://thirdworldcup.ru/index.php/" .. full_edit | local url_view = "https://thirdworldcup.ru/index.php/" .. full_edit | ||
local gear_img = "[[Файл:Gear icon.svg|12px|link=" .. url_view .. "]]" | local gear_img = "[[Файл:Gear icon.svg|12px|link=" .. url_view .. "]]" | ||
local edit_link = "[" .. url_edit .. ' <span title="Редактировать"> ' .. gear_img .. ' </span>]' | local edit_link = "[" .. url_edit .. ' <span title="Редактировать"> ' .. gear_img .. ' </span>]' | ||
| Строка 257: | Строка 274: | ||
for y, _ in pairs(N.champs) do table.insert(v_years, y) end | for y, _ in pairs(N.champs) do table.insert(v_years, y) end | ||
table.sort(v_years) | table.sort(v_years) | ||
local running_counts = {} | local running_counts = {} | ||
for i, y in ipairs(v_years) do | for i, y in ipairs(v_years) do | ||
local p_list = N.champs[y] | -- КОПИРУЕМ СПИСОК ПЕРЕД СОРТИРОВКОЙ | ||
local p_list = {} | |||
for _, p_n in ipairs(N.champs[y]) do table.insert(p_list, p_n) end | |||
table.sort(p_list) | |||
local fps = {} | local fps = {} | ||
for _, p_name in ipairs(p_list) do | for _, p_name in ipairs(p_list) do | ||
| Строка 279: | Строка 299: | ||
if show_nav.superchamps then add_nav({bg='DarkGray', icon='[[Файл:Суперчемпион.png|30px|]]', editName='Суперчемпионы', title='[[Суперчемпион]]ы', cat='[[Категория:Суперчемпионы]]', content=flat_chron(N.superchamps)}) end | if show_nav.superchamps then add_nav({bg='DarkGray', icon='[[Файл:Суперчемпион.png|30px|]]', editName='Суперчемпионы', title='[[Суперчемпион]]ы', cat='[[Категория:Суперчемпионы]]', content=flat_chron(N.superchamps)}) end | ||
if show_nav.zshar then add_nav({bg='PaleGreen', icon='[[Файл:ЗШар.png|30px|]]', editName='Лучшие игроки ЧТМ', title='[[Золотой Шар|Лучшие игроки ЧТМ]]', cat='[[Категория:Обладатели Золотого Шара]]', content=flat_chron(N.zshar)}) end | if show_nav.zshar then add_nav({bg='PaleGreen', icon='[[Файл:ЗШар.png|30px|]]', editName='Лучшие игроки ЧТМ', title='[[Золотой Шар|Лучшие игроки ЧТМ]]', cat='[[Категория:Обладатели Золотого Шара]]', content=flat_chron(N.zshar)}) end | ||
if show_nav.zbashmak then | if show_nav.zbashmak then | ||
local grp, sy, parts = {}, {}, {} | local grp, sy, parts = {}, {}, {} | ||
| Строка 312: | Строка 331: | ||
if show_nav.loyalty then | if show_nav.loyalty then | ||
table.sort( | -- КОПИРУЕМ МАССИВ ПЕРЕД СОРТИРОВКОЙ | ||
for _, i in ipairs( | local loy = {} | ||
for _, i in ipairs(N.loyalty) do table.insert(loy, i) end | |||
table.sort(loy, function(a,b) if a[1] ~= b[1] then return a[1] < b[1] end return a[2] < b[2] end) | |||
local pts = {} | |||
for _, i in ipairs(loy) do table.insert(pts, "[["..i[1].."]] — [["..i[2].."]] (''[["..(Teams.getName(i[3], 'short') or i[3]).."]]'')") end | |||
add_nav({bg='MediumAquamarine', noIcon=true, editName='Верность команде', title='Обладатели приза «[[Верность команде]]»', cat='[[Категория:Обладатели приза «Верность команде»]]', content='<span style="font-size:120%;">'..table.concat(pts, " • ")..'</span>'}) | add_nav({bg='MediumAquamarine', noIcon=true, editName='Верность команде', title='Обладатели приза «[[Верность команде]]»', cat='[[Категория:Обладатели приза «Верность команде»]]', content='<span style="font-size:120%;">'..table.concat(pts, " • ")..'</span>'}) | ||
end | end | ||
| Строка 347: | Строка 371: | ||
local out_str = Config.styles.wiki_templates | local out_str = Config.styles.wiki_templates | ||
if show_main then out_str = out_str .. html_main .. "\n" end | |||
if show_main then out_str = out_str .. "== Статистика ==\n" .. html_main .. "\n" end | |||
if show_matches then | if show_matches then | ||
if not show_main then out_str = out_str .. "== Список матчей ==\n" end | |||
out_str = out_str .. html_list .. "\n" | out_str = out_str .. html_list .. "\n" | ||
else | else | ||
Текущая версия от 03:17, 5 июня 2026
[просмотр] [просмотр кода] [история] [обновить]
Модуль для шаблона {{Автоматическая статистика/разработка}}.
Подгружает на страницу игрока таблицу со статистикой, полный список матчей начиная с ЧТМ-2022 и навигационные шаблоны. Вызов:
{{#invoke:Автоматическая статистика|render|Диман|СГ=1|Год=2020|Качество=ИС|sortable=no}}
Для тяжёлых статей рекомендуется выносить список матчей на отдельную подстраницу.
Есть функция медалек, но она слишком тяжёлая, загружается гораздо медленнее. Просьба не использовать на страницах основного пространства, а только в тестовом режиме:
{{#invoke:Автоматическая статистика|render|Диман|СГ=1|Год=2020|Качество=ИС|sortable=no|medals=yes}}
Список передаваемых параметров
{{#invoke:Автоматическая статистика|render<!-- Запуск модуля
-->|Диман<!-- Имя игрока, обязательный параметр
-->|СГ=1<!-- Если статья заняла какое-то место в голосовании за статью года, то оно указывается
-->|Год=2020<!-- Год, когда происходило голосование
-->|Качество=ИС<!-- Избранная (ИС) или хорошая (ХС) статья
-->|sortable=no<!-- Отключает сортировку таблицы статистики, делая её более компактной (по умолчанию — no)
-->|medals=no<!-- Отключает медали в таблице статистики, значительно снижая нагрузку на сервер (по умолчанию — no)
-->|main_table=no<!-- Отключает расчёт и вывод таблицы статистики (по умолчанию — yes)
-->|matches_list=no<!-- Отключает расчёт и вывод полного списка матчей (по умолчанию — yes)
-->|matches_link=<!-- В случае отключения списка матчей необходимо задать ссылку на подстраницу.
-->|navboxes=no<!-- Отключает расчёт и вывод навигационных шаблонов (по умолчанию — yes)
-->}}
Пожалуйста, добавляйте категории на страницу документации.-- ==========================================
-- Модуль:Автоматическая статистика
-- (Pure UI Render для PlayerStats JSON)
-- ==========================================
local p = {}
local Config = require('Module:Config')
local Teams = require('Module:Data/Teams')
p.row_defs = {
{ id = "matches", title = "[[" .. "Матчи|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Матчи</abbr>" .. "]]", era = 2022 },
{ id = "field_matches", title = "<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Матчи в поле</abbr>", era = 2022 },
{ id = "goals", title = "[[" .. "Список всех авторов голов на ЧТМ|Голы" .. "]]", era = 2006 },
{ id = "assists", title = "[[" .. "Передачи|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Передачи</abbr>" .. "]]", era = 2026 },
{ id = "avg_goals", title = "[[" .. "Средняя результативность|<abbr title=\"Подсчитывается начиная с ЧТМ-2022\">Ср. результативность</abbr>" .. "]]", era = 2022, is_avg = true, num = "goals", den = "field_matches" },
{ id = "avg_assists", title = "<abbr title=\"Подсчитывается начиная с ЧТМ-2026\">Передачи (ср. за матч)</abbr>", era = 2026, is_avg = true, num = "assists", den = "field_matches" },
{ id = "mvp", title = "[[" .. "Игрок матча" .. "]]", era = 2006 },
{ id = "matchday_prizes", title = "[[" .. "Призы игровых дней|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Призы игровых дней</abbr>" .. "]]", era = 2022 },
{ id = "matchday_places", title = "[[" .. "Призы игровых дней#Призовые места игровых дней|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Призовые места игр. дней</abbr>" .. "]]", era = 2022 },
{ id = "plus_minus", title = "[[" .. "Показатель полезности|<abbr title=\"Подсчитывается начиная с ЧТМ-2022\">Показатель полезности</abbr>" .. "]]", era = 2022, is_pm = true },
{ id = "mega_tricks", title = "[[" .. "Мега-трики" .. "]]", era = 2006 },
{ id = "assist_mega_tricks", title = "[[" .. "Мега-трики голевых передач|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Мега-трики голевых передач</abbr>" .. "]]", era = 2026 },
{ id = "head_goals", title = "[[" .. "Голы головой|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Голы головой</abbr>" .. "]]", era = 2022 },
{ id = "heel_goals", title = "[[" .. "Голы пяточкой|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Голы пяточкой</abbr>" .. "]]", era = 2026 },
{ id = "free_kick_goals", title = "[[" .. "Голы со штрафных|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Голы со штрафных</abbr>" .. "]]", era = 2026 },
{ id = "clearances", title = "[[" .. "Выносы из пустых|<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">Выносы из пустых</abbr>" .. "]]", era = 2022 },
{ id = "pens_scored", title = "[[" .. "Пенальти|Забитые пенальти" .. "]]", era = 2006 },
{ id = "pens_missed", title = "Незабитые пенальти", era = 2006 },
{ id = "pens_saved", title = "[[" .. "Список пенальти ЧТМ#Отбитые пенальти|Отбитые пенальти" .. "]]", era = 2006 },
{ id = "caused_pens", title = "[[" .. "Привезённые пенальти|<abbr title=\"Подсчитываются начиная с ЧТМ-2026\">Привезённые пенальти</abbr>" .. "]]", era = 2026 },
{ id = "mvp_goalie", title = "[[" .. "Игрок матча как вратарь" .. "]]", era = 2006 },
{ id = "goalie_goals", title = "<abbr title=\"Подсчитываются начиная с ЧТМ-2022\">[[" .. "Вратарские голы" .. "]]</abbr>", era = 2022 },
{ id = "clean_sheets", title = "[[" .. "Матчи на ноль" .. "]]", era = 2006 },
{ id = "yellow_cards", title = "<abbr title=\"Подсчитываются начиная с ЧТМ-2038\">[[" .. "Карточки|Жёлтые карточки" .. "]]</abbr>", era = 2038 },
{ id = "red_cards", title = "<abbr title=\"Подсчитываются начиная с ЧТМ-2038\">[[" .. "Карточки|Красные карточки" .. "]]</abbr>", era = 2038 },
{ id = "own_goals", title = "Автоголы", era = 2006 }
}
local function format_stage(st, let)
if st == "Группа" then return "гр. " .. (let or "")
elseif st == "Полуфинал" then return "1/2"
elseif st == "За 3-е место" then return "за 3-е"
elseif st == "Финал" then return "финал"
end
return st or ""
end
local function format_score(m)
local s1, s2 = m.score1 or "0", m.score2 or "0"
local sh1, sh2 = m.shootout1, m.shootout2
if m.role_team == 2 then
s1, s2 = m.score2 or "0", m.score1 or "0"
sh1, sh2 = m.shootout2, m.shootout1
end
local txt = s1 .. ":" .. s2
if m.aet then txt = txt .. "(ET)" end
if sh1 and sh2 then txt = txt .. "(пен." .. sh1 .. ":" .. sh2 .. ")" end
return txt
end
local function get_match_color(m)
if not m.is_official then return "" end
if m.role_team == 0 then return "lightgrey" end
local is_t1 = (m.role_team == 1)
local s1, s2 = tonumber(m.score1) or 0, tonumber(m.score2) or 0
local win, loss, draw = false, false, false
if m.shootout1 then
draw = true
if m.stage == "Финал" or m.stage == "финал" then
local p1, p2 = tonumber(m.shootout1) or 0, tonumber(m.shootout2) or 0
if (is_t1 and p1 > p2) or (not is_t1 and p2 > p1) then return "gold" else return "lightsalmon" end
end
return "palegoldenrod"
else
if s1 > s2 then win = is_t1; loss = not is_t1
elseif s2 > s1 then win = not is_t1; loss = is_t1
else draw = true end
if m.stage == "Финал" or m.stage == "финал" then
if win then return "gold" end
if loss then return "lightsalmon" end
return "palegoldenrod"
end
if draw then return "palegoldenrod" end
if win then return "lightgreen" end
return "lightsalmon"
end
end
function p.build_ui(player_name, args, compiled_data)
local sg_place = tonumber(args['СГ'] or args[2])
local quality = args['Качество'] or args[3]
local sg_year = args['Год'] or args['год'] or args['СГ_год'] or args[4] or "YYYY"
local sortable = (args.sortable ~= "no")
local show_main = (args.main_table ~= "no" and args.main_table ~= "0")
local show_matches = (args.matches_list ~= "no" and args.matches_list ~= "0")
local show_navboxes = (args.navboxes ~= "no" and args.navboxes ~= "0")
local matches_link = args.matches_link
local html_main = ""
local html_list = ""
local navs = {}
if show_main then
local classes = Config.styles.classes or "article-table ts-stickytableheader"
if sortable then classes = classes .. " sortable" else classes = string.gsub(classes, "sortable", "") end
local t_main = mw.html.create('table'):addClass(classes):attr('border', Config.styles.border or "1"):attr('cellspacing', Config.styles.cellspacing or "1"):attr('cellpadding', Config.styles.cellpadding or "1")
local header_tr = t_main:tag('tr')
header_tr:tag('th'):attr('scope', 'col'):cssText(Config.styles.header)
for _, year in ipairs(Config.years) do
local th = header_tr:tag('th'):attr('scope', 'col'):cssText(Config.styles.header)
local text = "[[" .. year .. "|'" .. string.sub(tostring(year), 3, 4) .. "]]"
if not compiled_data.played_years[year] then text = "<s>" .. text .. "</s>" end
th:wikitext(text)
end
header_tr:tag('th'):attr('scope', 'col'):cssText(Config.styles.header):wikitext("ВСЕГО")
for _, row in ipairs(p.row_defs) do
local r_tr = t_main:tag('tr')
r_tr:tag('td'):cssText("white-space:nowrap;text-align:center;"):wikitext(row.title)
for _, year in ipairs(Config.years) do
local td = r_tr:tag('td')
local style = "white-space:nowrap;text-align:center;"
if year < row.era then
td:cssText(style .. Config.styles.header)
else
local m_data = compiled_data.metrics[row.id] and compiled_data.metrics[row.id].years[year] or { val=0, num=0, den=0, color="" }
if m_data.color and m_data.color ~= "" then style = style .. m_data.color end
td:cssText(style)
if compiled_data.played_years[year] then
local val_str = ""
if row.is_avg then
val_str = (m_data.den > 0) and Config.utils.format_avg(m_data.num, m_data.den) or "0,00"
else
val_str = tostring(m_data.val)
if row.is_pm and m_data.val > 0 then val_str = "+" .. val_str end
end
td:wikitext(val_str)
end
end
end
local td_tot = r_tr:tag('td')
local style_tot = "white-space:nowrap;text-align:center;"
if row.era > compiled_data.last_played_year then
td_tot:cssText(style_tot):wikitext("—")
else
local m_tot = compiled_data.metrics[row.id] or { total_val=0, total_num=0, total_den=0, color="" }
if m_tot.color and m_tot.color ~= "" then style_tot = style_tot .. m_tot.color end
td_tot:cssText(style_tot)
local tot_str = ""
if row.is_avg then
tot_str = (m_tot.total_den > 0) and Config.utils.format_avg(m_tot.total_num, m_tot.total_den) or "0,00"
else
tot_str = tostring(m_tot.total_val)
if row.is_pm and m_tot.total_val > 0 then tot_str = "+" .. tot_str end
end
td_tot:wikitext("'''" .. tot_str .. "'''")
end
end
html_main = tostring(t_main)
end
if show_matches and compiled_data.player_matches_list then
-- 1. СНАЧАЛА копируем Read-Only прокси-массив в чистую Lua-таблицу
-- ipairs работает с JSON-прокси безупречно
local pml = {}
for _, m in ipairs(compiled_data.player_matches_list) do
table.insert(pml, m)
end
-- 2. ТЕПЕРЬ проверяем длину чистого массива pml, а не сломанного JSON-объекта
if #pml > 0 then
table.sort(pml, function(a, b) return a.num_hist < b.num_hist end)
local url_matches = "https://thirdworldcup.ru/index.php?title=%D0%9F%D0%BE%D0%B4%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%D0%B0:%D0%A0%D0%B0%D0%B7%D0%B2%D1%91%D1%80%D1%82%D0%BA%D0%B0_%D1%88%D0%B0%D0%B1%D0%BB%D0%BE%D0%BD%D0%BE%D0%B2/%D0%A1%D0%BF%D0%B8%D1%81%D0%BE%D0%BA_%D0%BC%D0%B0%D1%82%D1%87%D0%B5%D0%B9&action=edit"
local match_gear = " [[Файл:Gear icon.svg|12px|link=" .. url_matches .. "]] "
local list_classes = 'wikitable mw-collapsible'
if show_main then list_classes = list_classes .. ' mw-collapsed' end
local t_list = mw.html.create('table'):addClass(list_classes)
t_list:tag('tr'):tag('th'):attr('colspan', '9'):wikitext((compiled_data.played_before_2022 and "Полный список матчей начиная с ЧТМ-2022" or "Полный список матчей") .. match_gear)
local h_tr = t_list:tag('tr')
local cols = {"№", "Настоящая<br>дата", "ЧТМ<br>(№ матча)", "Раунд", "Команда", "Соперник", "Счёт", "Статистика", "Дополнительно"}
for _, col in ipairs(cols) do h_tr:tag('th'):attr('scope', 'col'):cssText(Config.styles.header):wikitext(col) end
local counter = 1
for _, m in ipairs(pml) do
local tr = t_list:tag('tr')
local bg_color = get_match_color(m)
local style_td = "white-space:nowrap;text-align:center;" .. (bg_color ~= "" and ("background-color:" .. bg_color .. ";") or "")
tr:tag('td'):cssText(style_td):wikitext(m.is_official and tostring(counter) or ""); if m.is_official then counter = counter + 1 end
tr:tag('td'):cssText(style_td):wikitext(m.is_official and (m.date ~= "" and (m.date:sub(9,10).."."..m.date:sub(6,7).."."..m.date:sub(1,4)) or "") or "")
tr:tag('td'):cssText(style_td):wikitext("[[" .. m.year .. "]] (" .. m.match_num_id .. ")")
tr:tag('td'):cssText(style_td):wikitext(format_stage(m.stage, m.letter))
local score_txt = format_score(m); if m.wikilink then score_txt = "'''[[" .. m.wikilink .. "|" .. score_txt .. "]]'''" end
if m.role_team == 0 then
tr:tag('td'):attr('colspan', '3'):cssText(style_td):wikitext("Вратарь ([[" .. Teams.getName(m.team1, 'short') .. "]] - [[" .. Teams.getName(m.team2, 'short') .. "]] - " .. score_txt .. ")")
else
tr:tag('td'):cssText(style_td):wikitext("[[" .. Teams.getName((m.role_team == 1) and m.team1 or m.team2, 'short') .. "]]")
tr:tag('td'):cssText(style_td):wikitext("[[" .. Teams.getName((m.role_team == 1) and m.team2 or m.team1, 'short') .. "]]")
tr:tag('td'):cssText(style_td):wikitext(score_txt)
end
local s_arr = {}
if m.goals > 0 then table.insert(s_arr, "'''" .. (m.goals > 1 and m.goals or "") .. "Г'''") end
if m.assists > 0 then table.insert(s_arr, "'''" .. (m.assists > 1 and m.assists or "") .. "П'''") end
if m.is_mvp then table.insert(s_arr, "'''<u>MVP</u>'''") end
tr:tag('td'):cssText(style_td):wikitext(table.concat(s_arr, ", "))
-- 3. РАСПАКОВЫВАЕМ m.events, чтобы корректно работали оператор длины (#) и table.concat
local safe_events = {}
if m.events then
for _, ev in ipairs(m.events) do table.insert(safe_events, ev) end
end
tr:tag('td'):cssText(style_td):wikitext(#safe_events > 0 and ("<small>" .. table.concat(safe_events, "<br>") .. "</small>") or "<small></small>")
end
html_list = tostring(t_list)
end
end
if show_navboxes then
local N = compiled_data.navbox_data
local show_nav = {
champs = (N.champ_counts and N.champ_counts[player_name] or 0) > 0, superchamps = false, zshar = false, zbashmak = false, elnur = false,
final_goals = (N.final_goals and N.final_goals[player_name] or 0) > 0, final_assists = (N.final_assists and N.final_assists[player_name] or 0) > 0,
club100 = (N.global_goals and N.global_goals[player_name] or 0) >= 100, loyalty = false,
org = (player_name == "Диман" or player_name == "Антон" or player_name == "Геныч")
}
local function has_p(lst) for _, i in ipairs(lst) do if i[2] == player_name then return true end end return false end
show_nav.superchamps = has_p(N.superchamps); show_nav.zshar = has_p(N.zshar); show_nav.zbashmak = has_p(N.zbashmak); show_nav.elnur = has_p(N.elnur); show_nav.loyalty = has_p(N.loyalty)
local function add_nav(args)
local icon_td = args.noIcon and '<td style="vertical-align:middle; text-align:left; padding:0; display:none;"></td>'
or string.format('<td style="vertical-align:middle; text-align:left; padding:0; width:%s;">%s</td>', args.iconW or '30px', args.icon)
local full_edit = mw.uri.encode("Шаблон:" .. args.editName, "PATH")
local url_edit = "https://thirdworldcup.ru/index.php?title=" .. full_edit .. "&action=edit"
local url_view = "https://thirdworldcup.ru/index.php/" .. full_edit
local gear_img = "[[Файл:Gear icon.svg|12px|link=" .. url_view .. "]]"
local edit_link = "[" .. url_edit .. ' <span title="Редактировать"> ' .. gear_img .. ' </span>]'
local html = string.format([[
<table style="clear:both; font-size:8pt; width:100%%; border-spacing:0; margin: 1px auto 1px auto; background:%s;" data-collapsetext="скрыть" data-expandtext="показать" class="toccolours mw-collapsible mw-collapsed ">
<tr style="color: #000000; background: %s; ">
%s
<th style="width:100%%; font-weight:bold; vertical-align:middle; text-align:center;"><div style="float:right; font-size:small; font-weight:normal;" class="plainlinks">%s</div><span style="font-size:140%%;">%s</span></th></tr>
<tr>
<td colspan="2" style="vertical-align:middle; text-align:center; padding:0;">
<table style="width:100%%; background-color:transparent ">%s</table>
</td>
</tr>
</table>%s]], args.bg, args.bg, icon_td, edit_link, args.title, args.content, args.cat)
table.insert(navs, html)
end
if show_nav.champs then
local rows, v_years = {}, {}
for y, _ in pairs(N.champs) do table.insert(v_years, y) end
table.sort(v_years)
local running_counts = {}
for i, y in ipairs(v_years) do
-- КОПИРУЕМ СПИСОК ПЕРЕД СОРТИРОВКОЙ
local p_list = {}
for _, p_n in ipairs(N.champs[y]) do table.insert(p_list, p_n) end
table.sort(p_list)
local fps = {}
for _, p_name in ipairs(p_list) do
running_counts[p_name] = (running_counts[p_name] or 0) + 1
table.insert(fps, "[["..p_name.."]]" .. (running_counts[p_name] > 1 and " ("..running_counts[p_name]..")" or ""))
end
table.insert(rows, string.format('<tr><td style="text-align:right; width:15%%; padding:0 0.5em; font-weight:bold; color: black; background: LightSteelBlue; ">[[Финал ЧТМ-%d|%d]]</td>\n<td style="text-align:left; padding:0 0.5em; "><span style="font-size:120%%;">%s%s</span></td></tr>', y, y, table.concat(fps, " • "), (i == #v_years and "" or "\n----")))
end
add_nav({bg='LightSteelBlue', icon='[[Файл:Star.png|30px|]]', editName='Игроки-чемпионы третьего мира', title='[[Список игроков-чемпионов третьего мира|Игроки-чемпионы третьего мира]]', cat='[[Категория:Игроки-чемпионы]]', content=table.concat(rows)})
end
local function flat_chron(list)
local parts = {}
for _, i in ipairs(list) do table.insert(parts, "[["..i[2].."]] ([["..i[1].."]])") end
return '<span style="font-size:120%;">' .. table.concat(parts, " • ") .. '</span>'
end
if show_nav.superchamps then add_nav({bg='DarkGray', icon='[[Файл:Суперчемпион.png|30px|]]', editName='Суперчемпионы', title='[[Суперчемпион]]ы', cat='[[Категория:Суперчемпионы]]', content=flat_chron(N.superchamps)}) end
if show_nav.zshar then add_nav({bg='PaleGreen', icon='[[Файл:ЗШар.png|30px|]]', editName='Лучшие игроки ЧТМ', title='[[Золотой Шар|Лучшие игроки ЧТМ]]', cat='[[Категория:Обладатели Золотого Шара]]', content=flat_chron(N.zshar)}) end
if show_nav.zbashmak then
local grp, sy, parts = {}, {}, {}
for _, i in ipairs(N.zbashmak) do if not grp[i[1]] then grp[i[1]]={g=i[3], p={}} end; table.insert(grp[i[1]].p, {i[2], i[4]}) end
for y in pairs(grp) do table.insert(sy, y) end; table.sort(sy)
for _, y in ipairs(sy) do
table.sort(grp[y].p, function(a,b) return a[1] < b[1] end); local ps = {}
for _, pi in ipairs(grp[y].p) do table.insert(ps, "[["..pi[1].."]] ([["..y.."]], [["..(Teams.getName(pi[2], 'short') or pi[2]).."]])") end
table.insert(parts, table.concat(ps, "; ") .. " — " .. grp[y].g)
end
add_nav({bg='palegoldenrod', icon='[[Файл:Золотой Башмак.png|42px|]]', iconW='42px', editName='Лучшие бомбардиры ЧТМ', title='[[Золотой Башмак|Лучшие бомбардиры ЧТМ]]', cat='[[Категория:Обладатели Золотого Башмака]]', content='<span style="font-size:120%;">' .. table.concat(parts, " • ") .. '</span>'})
end
if show_nav.elnur then add_nav({bg='Gainsboro', icon='[[Файл:Приз имени Эльнура.png|16px|]]', iconW='16px', editName='Лучшие вратари ЧТМ', title='[[Приз имени Эльнура|Лучшие вратари ЧТМ]]', cat='[[Категория:Обладатели Приза имени Эльнура]]', content=flat_chron(N.elnur)}) end
local function flat_actions(map)
local l, p = {}, {}
for n, c in pairs(map) do table.insert(l, {n, c}) end; table.sort(l, function(a,b) return a[1] < b[1] end)
for _, i in ipairs(l) do table.insert(p, "[["..i[1].."]] ("..i[2]..")") end
return '<span style="font-size:120%;">' .. table.concat(p, " • ") .. '</span>'
end
if show_nav.final_goals then add_nav({bg='IndianRed', icon='[[Файл:Kipsta ball.png|30px|]]', editName='Авторы голов в финале ЧТМ', title='Авторы голов в финале ЧТМ', cat='[[Категория:Авторы голов в финале]]', content=flat_actions(N.final_goals)}) end
if show_nav.final_assists then add_nav({bg='tan', icon='[[Файл:Assist.png|30px|]]', editName='Авторы голевых передач в финале ЧТМ', title='Авторы голевых передач в финале ЧТМ', cat='[[Категория:Авторы голевых передач в финале]]', content=flat_actions(N.final_assists)}) end
if show_nav.club100 then
local pl = {}
for p_name, g in pairs(N.global_goals) do if g >= 100 then table.insert(pl, p_name) end end; table.sort(pl)
for i, p_name in ipairs(pl) do pl[i] = "[["..p_name.."]]" end
add_nav({bg='plum', icon='[[Файл:Клуб 100.svg|30px|]]', editName='Клуб 100', title='[[Клуб 100]]', cat='[[Категория:Клуб 100]]', content='<span style="font-size:120%;">'..table.concat(pl, " • ")..'</span>'})
end
if show_nav.loyalty then
-- КОПИРУЕМ МАССИВ ПЕРЕД СОРТИРОВКОЙ
local loy = {}
for _, i in ipairs(N.loyalty) do table.insert(loy, i) end
table.sort(loy, function(a,b) if a[1] ~= b[1] then return a[1] < b[1] end return a[2] < b[2] end)
local pts = {}
for _, i in ipairs(loy) do table.insert(pts, "[["..i[1].."]] — [["..i[2].."]] (''[["..(Teams.getName(i[3], 'short') or i[3]).."]]'')") end
add_nav({bg='MediumAquamarine', noIcon=true, editName='Верность команде', title='Обладатели приза «[[Верность команде]]»', cat='[[Категория:Обладатели приза «Верность команде»]]', content='<span style="font-size:120%;">'..table.concat(pts, " • ")..'</span>'})
end
local gens, g_rows = { {t="Первое поколение<br>(2006—2007)", l={}}, {t="Второе поколение<br>(2011—2013)", l={}}, {t="Третье поколение<br>(2020—<abbr title=\"настоящее время\" class=\"nowrap\">н. в.</abbr>)", l={}} }, {}
for p_name, y in pairs(N.debuts) do if y <= 2018 then table.insert(gens[1].l, p_name) elseif y <= 2034 then table.insert(gens[2].l, p_name) else table.insert(gens[3].l, p_name) end end
for i, g in ipairs(gens) do
if #g.l > 0 then
table.sort(g.l); local p_strs = {}
for _, p_name in ipairs(g.l) do table.insert(p_strs, "[["..p_name.."]]"..string.rep("★", N.champ_counts[p_name] or 0)) end
table.insert(g_rows, string.format('<tr><td style="text-align:right; width:15%%; padding:0 0.5em; font-weight:bold; color: black; background: Thistle; ">%s</td>\n<td style="text-align:left; padding:0 0.5em; "><span style="font-size:120%%;">%s%s</span></td></tr>', g.t, table.concat(p_strs, " • "), (i == #gens and "" or "\n----")))
end
end
add_nav({bg='Thistle', icon='[[Файл:Logo.png|32px|]]', iconW='32px', editName='Игроки ЧТМ', title='Игроки ЧТМ', cat='[[Категория:Игроки]]', content=table.concat(g_rows)})
if show_nav.org then table.insert(navs, '{{Организация ЧТМ}}') end
end
local function render_amboxes()
local out = {}
if sg_place == 1 then
table.insert(out, '<indicator name="1">[[Файл:Лучшая статья года.png|36px|link=ЧТМ:Статьи года|Эта статья была признана лучшей статьёй ЧТМ Вики '..sg_year..' года]]</indicator>\n{{Ambox\n|id = 1-message\n|name = Статья года\n|type = good\n|image = [[Файл:Лучшая статья года.png|24px|link=ЧТМ:Статьи года|alt=✰]]\n|text = Эта статья была признана \'\'\'[[ЧТМ Вики:Статьи года|лучшей статьёй]]\'\'\' ЧТМ Вики '..sg_year..' года.\n}}[[Категория:Лучшие статьи года]][[Категория:Статьи года]]')
elseif sg_place and sg_place >= 2 and sg_place <= 10 then
table.insert(out, '<indicator name="2">[[Файл:Статья года.png|32px|link=ЧТМ:Статьи года|Эта статья заняла '..sg_place..' место в голосовании за звание лучшей статьи '..sg_year..' года]]</indicator>\n{{Ambox\n|id = 2-message\n|name = Статья года\n|type = good\n|image = [[Файл:Статья года.png|24px|link=ЧТМ:Статьи года|alt=✰]]\n|text = Эта статья заняла '..sg_place..' место в голосовании за звание \'\'\'[[ЧТМ Вики:Статьи года|лучшей статьи]]\'\'\' '..sg_year..' года.\n}}[[Категория:Статьи года]]')
end
if quality == 'ИС' then
table.insert(out, '<indicator name="3">[[Файл:Skew star.png|28px|link=ЧТМ:Избранные статьи|Эта статья входит в число избранных статей ЧТМ Вики]]</indicator>\n{{Ambox\n|id = 3-message\n|name = Избранная статья\n|type = good\n|image = [[Файл:Skew star.png|24px|link=ЧТМ:Избранные статьи|alt=✰]]\n|text = Эта статья входит в число [[ЧТМ:Избранные статьи|избранных статей]] ЧТМ Вики.\n}}[[Категория:Избранные статьи]]')
elseif quality == 'ХС' then
table.insert(out, '<indicator name="4">[[Файл:Blue star.png|28px|link=ЧТМ:Хорошие статьи|Эта статья входит в число хороших статей ЧТМ Вики]]</indicator>\n{{Ambox\n|id = 4-message\n|name = Хорошая статья\n|type = good\n|image = [[Файл:Blue star.png|24px|link=ЧТМ:Хорошие статьи|alt=✰]]\n|text = Эта статья входит в число [[ЧТМ:Хорошие статьи|хороших статей]] ЧТМ Вики.\n}}[[Категория:Хорошие статьи]]')
end
return table.concat(out, "\n")
end
local out_str = Config.styles.wiki_templates
if show_main then out_str = out_str .. "== Статистика ==\n" .. html_main .. "\n" end
if show_matches then
if not show_main then out_str = out_str .. "== Список матчей ==\n" end
out_str = out_str .. html_list .. "\n"
else
local link_target = matches_link or "/Список матчей"
out_str = out_str .. "'''[[" .. link_target .. "|Полный список матчей]]'''.\n"
end
out_str = out_str .. render_amboxes() .. "\n"
if show_navboxes then out_str = out_str .. table.concat(navs, "\n") end
return out_str
end
return p