Module:Soldier: Difference between revisions
Infobox Teams row: merge IPW fields, |teams=, and research-note team codes |
Story cue + same class/team rails |
||
| Line 2,265: | Line 2,265: | ||
end | end | ||
return tostring(wrap) | return tostring(wrap) | ||
end | |||
local function cargoRows(tables, fields, where, limit, orderBy) | |||
if not mw.ext or not mw.ext.cargo or not mw.ext.cargo.query then | |||
return nil | |||
end | |||
local opts = { | |||
where = where, | |||
limit = limit or 8, | |||
} | |||
if orderBy and orderBy ~= '' then | |||
opts.orderBy = orderBy | |||
end | |||
local ok, result = pcall(mw.ext.cargo.query, tables, fields, opts) | |||
if not ok or type(result) ~= 'table' then | |||
return nil | |||
end | |||
return result | |||
end | |||
local function rowField(row, ...) | |||
for i = 1, select('#', ...) do | |||
local key = select(i, ...) | |||
local v = row[key] | |||
if v ~= nil and trim(tostring(v)) ~= '' then | |||
return trim(tostring(v)) | |||
end | |||
end | |||
return '' | |||
end | |||
local function titleToCaption(title) | |||
title = trim(title) | |||
local surname, given = mw.ustring.match(title, '^([^,]+),%s*(.-)%s*%(%d') | |||
if surname and given then | |||
return trim(given .. ' ' .. surname) | |||
end | |||
return title | |||
end | |||
local function displayFromCargoRow(row) | |||
local page = rowField(row, 'pageName', '_pageName') | |||
local surname = rowField(row, 'Surname') | |||
local first = rowField(row, 'First_name', 'First name') | |||
local middle = rowField(row, 'Middle_name', 'Middle name') | |||
local given = trim(first .. (middle ~= '' and (' ' .. middle) or '')) | |||
local caption | |||
if given ~= '' and surname ~= '' then | |||
caption = given .. ' ' .. surname | |||
elseif page ~= '' then | |||
caption = titleToCaption(page) | |||
else | |||
caption = surname | |||
end | |||
if page == '' and surname ~= '' then | |||
local asn = rowField(row, 'ASN') | |||
if asn ~= '' then | |||
page = surname .. ', ' .. (given ~= '' and given or first) .. ' (' .. asn .. ')' | |||
end | |||
end | |||
return page, caption | |||
end | |||
local function linkList(rows, skipAsn, skipPage, maxLinks) | |||
local links = {} | |||
local seen = {} | |||
for _, row in ipairs(rows or {}) do | |||
local asn = rowField(row, 'ASN') | |||
local page, caption = displayFromCargoRow(row) | |||
if caption == '' and page ~= '' then | |||
caption = titleToCaption(page) | |||
end | |||
if page ~= '' and page ~= skipPage and asn ~= skipAsn and not seen[page] then | |||
seen[page] = true | |||
table.insert(links, string.format('[[%s|%s]]', page, caption)) | |||
if #links >= maxLinks then | |||
break | |||
end | |||
end | |||
end | |||
return links | |||
end | |||
local function classFullWhere(classNum) | |||
-- Prefer Class_number__full: the Class_number HOLDS index is corrupted on some hosts. | |||
local n = tostring(classNum or '') | |||
n = mw.ustring.gsub(n, '[^0-9A-Za-z%-]', '') | |||
if n == '' then | |||
return nil | |||
end | |||
return string.format( | |||
'Class_number__full="%s" OR Class_number__full LIKE "%s;%%" OR Class_number__full LIKE "%%;%s" OR Class_number__full LIKE "%%;%s;%%"', | |||
n, | |||
n, | |||
n, | |||
n | |||
) | |||
end | |||
function p.storyCue(frame) | |||
local story = parentArg(frame, 'story') | |||
if story == '' then | |||
return '' | |||
end | |||
story = mw.ustring.gsub(story, '^%[%[', '') | |||
story = mw.ustring.gsub(story, '%]%]$', '') | |||
local storyTitle, storyLabel = mw.ustring.match(story, '^([^|]+)|(.+)$') | |||
if not storyTitle then | |||
storyTitle = story | |||
storyLabel = nil | |||
end | |||
storyTitle = trim(storyTitle) | |||
if storyLabel then | |||
storyLabel = trim(storyLabel) | |||
end | |||
if not storyLabel or storyLabel == '' then | |||
storyLabel = mw.ustring.match(storyTitle, '([^/]+)$') or storyTitle | |||
end | |||
local name = displayName(frame) | |||
return string.format( | |||
'<div class="soldier-story-cue">' | |||
.. '<span class="soldier-story-cue-label">Full story</span> ' | |||
.. 'Read more about %s in [[%s|%s]] on \'\'[[The Stories]]\'\'.' | |||
.. '</div>', | |||
name, | |||
storyTitle, | |||
storyLabel | |||
) | |||
end | |||
function p.relatedSoldiers(frame) | |||
local asn = parentArg(frame, 'asn') | |||
local pageTitle = mw.title.getCurrentTitle().prefixedText | |||
local classRaw = parentArg(frame, 'class_number') | |||
local ipwGe = parentArg(frame, 'ipw_ge') | |||
local ipwIt = parentArg(frame, 'ipw_it') | |||
local sections = {} | |||
local function addTeam(label, teamPage, where) | |||
local rows = cargoRows( | |||
'Soldiers', | |||
'ASN,Surname,First_name,Middle_name,_pageName=pageName', | |||
where, | |||
8, | |||
'Surname' | |||
) | |||
local links = linkList(rows, asn, pageTitle, 8) | |||
local head = string.format('[[%s|%s]]', teamPage, label) | |||
local cat = 'Category:' .. teamPage | |||
if #links > 0 then | |||
table.insert( | |||
sections, | |||
'<div class="soldier-related-block"><div class="soldier-related-label">Team — ' | |||
.. head | |||
.. '</div><div class="soldier-related-links">' | |||
.. table.concat(links, ' · ') | |||
.. ' · [[' | |||
.. cat | |||
.. '|full roster]]</div></div>' | |||
) | |||
else | |||
table.insert( | |||
sections, | |||
'<div class="soldier-related-block"><div class="soldier-related-label">Team</div>' | |||
.. '<div class="soldier-related-links">Also assigned to ' | |||
.. head | |||
.. ' · [[' | |||
.. cat | |||
.. '|browse teammates]]</div></div>' | |||
) | |||
end | |||
end | |||
if ipwGe ~= '' then | |||
local num = mw.ustring.match(ipwGe, '(%d+)') or ipwGe | |||
addTeam('IPW ' .. num, 'Team IPW ' .. num, string.format('IPW_German="%s"', num)) | |||
end | |||
if ipwIt ~= '' then | |||
local num = mw.ustring.match(ipwIt, '(%d+)') or ipwIt | |||
addTeam( | |||
'IPW Italian ' .. num, | |||
'Team IPW Italian ' .. num, | |||
string.format('IPW_Italian="%s"', num) | |||
) | |||
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 | |||
if #sections == 0 then | |||
return '' | |||
end | |||
return '<div class="soldier-related">' | |||
.. '<div class="soldier-related-heading">Same class and team</div>' | |||
.. table.concat(sections, '\n') | |||
.. '</div>' | |||
end | end | ||
return p | return p | ||