Related rail: include MII/|teams=/notes teams; roster co-assignment note
Related rail: teams only; names from team categories (incl. MII)
Line 2,396: Line 2,396:


function p.relatedSoldiers(frame)
function p.relatedSoldiers(frame)
local asn = parentArg(frame, 'asn')
local pageTitle = mw.title.getCurrentTitle().prefixedText
local pageTitle = mw.title.getCurrentTitle().prefixedText
local classRaw = parentArg(frame, 'class_number')
local sections = {}
local sections = {}


local function addTeamBlock(teamName, where)
-- Members from the team category (works for IPW, MII, and note-derived teams).
local teamPage = 'Team ' .. teamName
-- Do not sample classmates: classes are huge and a short list looks arbitrary.
local head = teamNameLink(teamName)
local function teamCategoryMemberLinks(teamName, maxLinks)
local cat = 'Category:' .. teamPage
maxLinks = maxLinks or 24
local ok, html = pcall(function()
return frame:preprocess(
string.format(
'{{#categorytree:%s|mode=pages|hideroot=on|namespaces=0}}',
'Team ' .. teamName
)
)
end)
if not ok or type(html) ~= 'string' or html == '' then
return {}
end
local links = {}
local links = {}
if where then
local seen = {}
local rows = cargoRows(
for title in mw.ustring.gmatch(html, 'title="([^"]+)"') do
'Soldiers',
title = mw.text.decode(title, true)
'ASN,Surname,First_name,Middle_name,_pageName=pageName',
if (
where,
title ~= pageTitle
8,
and not seen[title]
'Surname'
and mw.ustring.find(title, '%(%d')
)
and not mw.ustring.find(title, '^Category:')
links = linkList(rows, asn, pageTitle, 8)
) then
seen[title] = true
table.insert(
links,
string.format('[[%s|%s]]', title, titleToCaption(title))
)
if #links >= maxLinks then
break
end
end
end
end
return links
end
local function addTeamBlock(teamName)
local head = teamNameLink(teamName)
local cat = 'Category:Team ' .. teamName
local links = teamCategoryMemberLinks(teamName, 24)
if #links > 0 then
if #links > 0 then
table.insert(
table.insert(
Line 2,429: Line 2,453:
)
)
else
else
-- MII and other non-Cargo teams: still surface the team page/category.
table.insert(
table.insert(
sections,
sections,
Line 2,455: Line 2,478:


for _, teamName in ipairs(teamNames) do
for _, teamName in ipairs(teamNames) do
local where = nil
addTeamBlock(teamName)
local geNum = mw.ustring.match(teamName, '^IPW (%d+)$')
local itCode = mw.ustring.match(teamName, '^IPW Italian (.+)$')
if geNum then
where = string.format('IPW_German="%s"', geNum)
elseif itCode then
where = string.format('IPW_Italian="%s"', itCode)
end
addTeamBlock(teamName, where)
end
 
local classes = {}
if classRaw ~= '' then
for part in mw.text.gsplit(classRaw, ';', true) do
part = trim(part)
if part ~= '' then
table.insert(classes, part)
end
end
end
for _, classNum in ipairs(classes) do
local where = classFullWhere(classNum)
local rows = where
and cargoRows(
'Soldiers',
'ASN,Surname,First_name,Middle_name,_pageName=pageName',
where,
8,
'Surname'
)
or nil
local links = linkList(rows, asn, pageTitle, 8)
local classPage = 'Class ' .. classNum
local cat = 'Category:Class ' .. classNum
if #links > 0 then
table.insert(
sections,
'<div class="soldier-related-block"><div class="soldier-related-label">Class — [['
.. classPage
.. ']]</div><div class="soldier-related-links">'
.. table.concat(links, ' · ')
.. ' · [['
.. cat
.. '|full class]]</div></div>'
)
else
table.insert(
sections,
'<div class="soldier-related-block"><div class="soldier-related-label">Class</div>'
.. '<div class="soldier-related-links">Also trained in [['
.. classPage
.. ']] · [['
.. cat
.. '|browse classmates]]</div></div>'
)
end
end
end


Line 2,517: Line 2,485:
end
end
return '<div class="soldier-related">'
return '<div class="soldier-related">'
.. '<div class="soldier-related-heading">Same class and team</div>'
.. '<div class="soldier-related-heading">Same team</div>'
.. table.concat(sections, '\n')
.. table.concat(sections, '\n')
.. '<div class="soldier-related-note">These are other soldiers listed on the same class or team roster. '
.. '<div class="soldier-related-note">These are other soldiers listed on the same team roster. '
.. 'People moved between teams; overlapping service dates are not always documented.</div>'
.. 'People moved between teams; overlapping service dates are not always documented.</div>'
.. '</div>'
.. '</div>'