|
|
| Line 3: |
Line 3: |
| local function trim(s) | | local function trim(s) |
| return mw.text.trim(tostring(s or '')) | | return mw.text.trim(tostring(s or '')) |
| end
| |
|
| |
| local function countChar(s, ch)
| |
| local _, n = mw.ustring.gsub(s, ch, '')
| |
| return n
| |
| end
| |
|
| |
| local function tidyDisplay(s)
| |
| s = trim(s)
| |
| if s == '' then
| |
| return ''
| |
| end
| |
| s = mw.text.decode(s, true)
| |
| s = mw.ustring.gsub(s, mw.ustring.char(160), ' ')
| |
| s = mw.ustring.gsub(s, mw.ustring.char(0xFFFD), '')
| |
| s = mw.ustring.gsub(s, mw.ustring.char(0x200B), '')
| |
| s = trim(s)
| |
| local lower = mw.ustring.lower(s)
| |
| if lower == '#n/a' or lower == 'n/a' or lower == 'none' or lower == 'null' or lower == '-' then
| |
| return ''
| |
| end
| |
| if s == '.' or s == '?' then
| |
| return ''
| |
| end
| |
| local prev
| |
| repeat
| |
| prev = s
| |
| s = mw.ustring.gsub(s, '""', '"')
| |
| until s == prev
| |
| s = trim(s)
| |
|
| |
| local changed = true
| |
| while changed and mw.ustring.len(s) >= 2 do
| |
| changed = false
| |
| local first = mw.ustring.sub(s, 1, 1)
| |
| local last = mw.ustring.sub(s, -1)
| |
| if first == '"' and last == '"' then
| |
| local inner = mw.ustring.sub(s, 2, -2)
| |
| if countChar(inner, '"') == 0 then
| |
| s = trim(inner)
| |
| changed = true
| |
| elseif countChar(s, '"') % 2 == 1 then
| |
| local second = mw.ustring.find(s, '"', 2, true)
| |
| local slen = mw.ustring.len(s)
| |
| if second and second + 1 < slen then
| |
| local nxt = mw.ustring.sub(s, second + 1, second + 1)
| |
| if mw.ustring.find(nxt, '%w') then
| |
| s = mw.ustring.sub(s, 2)
| |
| else
| |
| s = mw.ustring.sub(s, 1, -2)
| |
| end
| |
| else
| |
| s = mw.ustring.sub(s, 1, -2)
| |
| end
| |
| s = trim(s)
| |
| changed = true
| |
| end
| |
| elseif first == "'" and last == "'" then
| |
| local inner = mw.ustring.sub(s, 2, -2)
| |
| if not mw.ustring.find(inner, "'", 1, true) then
| |
| s = trim(inner)
| |
| changed = true
| |
| end
| |
| end
| |
| end
| |
|
| |
| local q = countChar(s, '"')
| |
| local first = mw.ustring.sub(s, 1, 1)
| |
| local last = mw.ustring.sub(s, -1)
| |
| if first == '"' and q == 1 and last ~= '"' then
| |
| s = trim(mw.ustring.sub(s, 2))
| |
| end
| |
| last = mw.ustring.sub(s, -1)
| |
| first = mw.ustring.sub(s, 1, 1)
| |
| q = countChar(s, '"')
| |
| if last == '"' and q == 1 and first ~= '"' then
| |
| s = trim(mw.ustring.sub(s, 1, -2))
| |
| end
| |
| s = mw.ustring.gsub(s, '^\\+', '')
| |
| s = trim(s)
| |
| if s == '"' or s == "'" or s == '.' or s == '?' or s == '\\' then
| |
| return ''
| |
| end
| |
| s = mw.ustring.gsub(s, '%s+', ' ')
| |
| return trim(s)
| |
| end | | end |
|
| |
|
| local function parentArg(frame, name) | | local function parentArg(frame, name) |
| local parent = frame:getParent() | | local parent = frame:getParent() |
| local raw
| |
| if parent and parent.args[name] then | | if parent and parent.args[name] then |
| raw = parent.args[name] | | return trim(parent.args[name]) |
| else
| |
| raw = frame.args[name]
| |
| end | | end |
| return tidyDisplay(raw) | | return trim(frame.args[name]) |
| end
| |
| | |
| local ACRONYMS = {
| |
| US = true, USA = true, POW = true, IPW = true, MII = true, OSS = true,
| |
| MITC = true, ASN = true, WWII = true, NARA = true, DC = true, DEML = true,
| |
| CSU = true, ASTP = true, CAC = true, KIA = true, MIA = true, NG = true,
| |
| MRBC = true, PACMIRS = true, GED = true, MITU = true, RDC = true,
| |
| }
| |
| | |
| local SMALL_WORDS = {
| |
| and = true, of = true, the = true, for = true, to = true, in = true,
| |
| a = true, an = true, at = true, by = true, or = true,
| |
| }
| |
| | |
| local STATE_NAME = {
| |
| alabama = 'Alabama', alaska = 'Alaska', arizona = 'Arizona', arkansas = 'Arkansas',
| |
| california = 'California', colorado = 'Colorado', connecticut = 'Connecticut',
| |
| delaware = 'Delaware', florida = 'Florida', georgia = 'Georgia', hawaii = 'Hawaii',
| |
| idaho = 'Idaho', illinois = 'Illinois', indiana = 'Indiana', iowa = 'Iowa',
| |
| kansas = 'Kansas', kentucky = 'Kentucky', louisiana = 'Louisiana', maine = 'Maine',
| |
| maryland = 'Maryland', massachusetts = 'Massachusetts', michigan = 'Michigan',
| |
| minnesota = 'Minnesota', mississippi = 'Mississippi', missouri = 'Missouri',
| |
| montana = 'Montana', nebraska = 'Nebraska', nevada = 'Nevada', ohio = 'Ohio',
| |
| oklahoma = 'Oklahoma', oregon = 'Oregon', pennsylvania = 'Pennsylvania',
| |
| tennessee = 'Tennessee', texas = 'Texas', utah = 'Utah', vermont = 'Vermont',
| |
| virginia = 'Virginia', washington = 'Washington', wisconsin = 'Wisconsin',
| |
| wyoming = 'Wyoming',
| |
| }
| |
| | |
| local STATE_ABBR = {
| |
| al = 'Alabama', ak = 'Alaska', az = 'Arizona', ar = 'Arkansas', ca = 'California',
| |
| co = 'Colorado', ct = 'Connecticut', de = 'Delaware', fl = 'Florida', ga = 'Georgia',
| |
| hi = 'Hawaii', id = 'Idaho', il = 'Illinois', ['in'] = 'Indiana', ia = 'Iowa',
| |
| ks = 'Kansas', ky = 'Kentucky', la = 'Louisiana', me = 'Maine', md = 'Maryland',
| |
| ma = 'Massachusetts', mi = 'Michigan', mn = 'Minnesota', ms = 'Mississippi',
| |
| mo = 'Missouri', mt = 'Montana', ne = 'Nebraska', nv = 'Nevada', nh = 'New Hampshire',
| |
| nj = 'New Jersey', nm = 'New Mexico', ny = 'New York', nc = 'North Carolina',
| |
| nd = 'North Dakota', oh = 'Ohio', ok = 'Oklahoma', ['or'] = 'Oregon', pa = 'Pennsylvania',
| |
| ri = 'Rhode Island', sc = 'South Carolina', sd = 'South Dakota', tn = 'Tennessee',
| |
| tx = 'Texas', ut = 'Utah', vt = 'Vermont', va = 'Virginia', wa = 'Washington',
| |
| wv = 'West Virginia', wi = 'Wisconsin', wy = 'Wyoming', dc = 'Washington, D.C.',
| |
| }
| |
| | |
| local TWO_WORD_STATE = {
| |
| ['new hampshire'] = 'New Hampshire',
| |
| ['new jersey'] = 'New Jersey',
| |
| ['new mexico'] = 'New Mexico',
| |
| ['new york'] = 'New York',
| |
| ['north carolina'] = 'North Carolina',
| |
| ['north dakota'] = 'North Dakota',
| |
| ['rhode island'] = 'Rhode Island',
| |
| ['south carolina'] = 'South Carolina',
| |
| ['south dakota'] = 'South Dakota',
| |
| ['west virginia'] = 'West Virginia',
| |
| }
| |
| | |
| local NEGATIVE_PHRASES = {
| |
| 'unsatisfactory', 'failed class', 'failed as', 'failure', 'flunk',
| |
| 'washed out', 'wash out', 'washout', 'kicked out', 'kick out',
| |
| 'dismissed', 'expelled', 'poor performance', 'poor work', 'poor grades',
| |
| 'awol', 'court-martial', 'court martial', 'disciplinary',
| |
| 'discharged for cause', 'dropped out', 'dropped from', 'also dropped',
| |
| 'physically unfit', 'unfit for', 'relieved prior', 'relieved of',
| |
| 'kicked', 'eliminated from', 'not graduated', 'did not graduate',
| |
| }
| |
| | |
| local function splitWords(s)
| |
| local words = {}
| |
| for w in mw.text.gsplit(s, ' ', true) do
| |
| if w ~= '' then
| |
| table.insert(words, w)
| |
| end
| |
| end
| |
| return words
| |
| end
| |
| | |
| local function isAllCapsPhrase(s)
| |
| local letters = mw.ustring.gsub(s, '[^%a]', '')
| |
| if mw.ustring.len(letters) < 2 then
| |
| return false
| |
| end
| |
| return letters == mw.ustring.upper(letters)
| |
| end
| |
| | |
| local function prettyTitle(s, keepSmall)
| |
| s = trim(s)
| |
| if s == '' then
| |
| return s
| |
| end
| |
| local words = splitWords(s)
| |
| local out = {}
| |
| for i, w in ipairs(words) do
| |
| local bare = mw.ustring.gsub(w, '[^%a]', '')
| |
| local up = mw.ustring.upper(bare)
| |
| if ACRONYMS[up] then
| |
| table.insert(out, mw.ustring.gsub(w, bare, up, 1))
| |
| else
| |
| local low = mw.ustring.lower(w)
| |
| local lowBare = mw.ustring.lower(bare)
| |
| if keepSmall and i > 1 and SMALL_WORDS[lowBare] then
| |
| table.insert(out, mw.ustring.lower(w))
| |
| else
| |
| local first = mw.ustring.upper(mw.ustring.sub(low, 1, 1))
| |
| table.insert(out, first .. mw.ustring.sub(low, 2))
| |
| end
| |
| end
| |
| end
| |
| return table.concat(out, ' ')
| |
| end | | end |
|
| |
|
| local function titleCase(s) | | local function titleCase(s) |
| return prettyTitle(s, false)
| |
| end
| |
|
| |
| local function looksLikeCode(s)
| |
| s = trim(s)
| |
| if s == '' then
| |
| return true
| |
| end
| |
| if mw.ustring.find(s, '%d') and mw.ustring.len(s) <= 8 and not mw.ustring.find(s, ' ') then
| |
| return true
| |
| end
| |
| if mw.ustring.len(s) <= 3 and not mw.ustring.find(s, ' ') then
| |
| return true
| |
| end
| |
| return false
| |
| end
| |
|
| |
| local function prettyPlace(s)
| |
| s = trim(s) | | s = trim(s) |
| if s == '' then | | if s == '' then |
| return s | | return s |
| end | | end |
| local compact = mw.ustring.lower(s) | | s = mw.ustring.lower(s) |
| compact = mw.ustring.gsub(compact, '[.,]', '') | | return mw.ustring.gsub(s, "(%a)([%w']*)", function(first, rest) |
| compact = mw.ustring.gsub(compact, '%s+', ' ')
| | return mw.ustring.upper(first) .. rest |
| compact = trim(compact)
| | end) |
| if compact == 'washington dc' or compact == 'washington d c'
| |
| or compact == 'district of columbia' or compact == 'washington dc' then
| |
| return 'Washington, D.C.'
| |
| end
| |
| if mw.ustring.find(compact, ' washington dc$') or mw.ustring.find(compact, ' washington d c$') then
| |
| local city = mw.ustring.gsub(s, '[Ww][Aa][Ss][Hh][Ii][Nn][Gg][Tt][Oo][Nn]%s+[Dd]%.?%s*[Cc]%.?$', '')
| |
| city = prettyTitle(trim(city), false)
| |
| if city ~= '' then
| |
| return city .. ', Washington, D.C.'
| |
| end
| |
| return 'Washington, D.C.'
| |
| end
| |
| if mw.ustring.find(s, ',', 1, true) then
| |
| local bits = {}
| |
| for part in mw.text.gsplit(s, ',', true) do
| |
| part = trim(part)
| |
| if part ~= '' then
| |
| table.insert(bits, prettyTitle(part, false))
| |
| end
| |
| end
| |
| return table.concat(bits, ', ')
| |
| end
| |
| local words = splitWords(s)
| |
| if #words >= 2 then
| |
| local last2 = mw.ustring.lower(words[#words - 1] .. ' ' .. words[#words])
| |
| last2 = mw.ustring.gsub(last2, '%.', '')
| |
| if TWO_WORD_STATE[last2] then
| |
| local city = {}
| |
| for i = 1, #words - 2 do
| |
| table.insert(city, words[i])
| |
| end
| |
| if #city > 0 then
| |
| return prettyTitle(table.concat(city, ' '), false) .. ', ' .. TWO_WORD_STATE[last2]
| |
| end
| |
| return TWO_WORD_STATE[last2]
| |
| end
| |
| end
| |
| if #words >= 1 then
| |
| local last = mw.ustring.lower(words[#words])
| |
| last = mw.ustring.gsub(last, '%.', '')
| |
| local state = STATE_NAME[last] or STATE_ABBR[last]
| |
| if state then
| |
| if #words >= 2 then
| |
| local city = {}
| |
| for i = 1, #words - 1 do
| |
| table.insert(city, words[i])
| |
| end
| |
| return prettyTitle(table.concat(city, ' '), false) .. ', ' .. state
| |
| end
| |
| return state
| |
| end
| |
| end
| |
| if isAllCapsPhrase(s) then
| |
| return prettyTitle(s, false)
| |
| end
| |
| return s
| |
| end
| |
| | |
| local function prettyProse(s)
| |
| s = trim(s)
| |
| if s == '' or looksLikeCode(s) then
| |
| return s
| |
| end
| |
| if isAllCapsPhrase(s) or prettyPlace(s) ~= s then
| |
| local placed = prettyPlace(s)
| |
| if placed ~= s then
| |
| return placed
| |
| end
| |
| end
| |
| if isAllCapsPhrase(s) then
| |
| return prettyTitle(s, true)
| |
| end
| |
| return s
| |
| end
| |
| | |
| local function prettyNamePart(s)
| |
| s = trim(s)
| |
| if s == '' then
| |
| return s
| |
| end
| |
| if isAllCapsPhrase(s) then
| |
| return prettyTitle(s, false) | |
| end
| |
| return s
| |
| end
| |
| | |
| local function isNegativeClause(s)
| |
| local lower = mw.ustring.lower(s)
| |
| if lower == 'failed' or mw.ustring.find(lower, '^failed%s') or mw.ustring.find(lower, '%sfailed%s') or mw.ustring.find(lower, '%sfailed$') then
| |
| return true
| |
| end | |
| for _, phrase in ipairs(NEGATIVE_PHRASES) do
| |
| if mw.ustring.find(lower, phrase, 1, true) then
| |
| return true
| |
| end
| |
| end
| |
| return false
| |
| end
| |
| | |
| local function sanitizeNote(s)
| |
| s = tidyDisplay(s)
| |
| if s == '' then
| |
| return ''
| |
| end
| |
| local lower = mw.ustring.lower(s)
| |
| if mw.ustring.find(lower, 'no notes were in the source', 1, true) then
| |
| return ''
| |
| end
| |
| local kept = {}
| |
| for clause in mw.text.gsplit(s, ';', true) do
| |
| clause = trim(clause)
| |
| if clause ~= '' then
| |
| for sent in mw.text.gsplit(clause, '. ', true) do
| |
| sent = trim(sent)
| |
| sent = mw.ustring.gsub(sent, '%.$', '')
| |
| if sent ~= '' and not isNegativeClause(sent) then
| |
| table.insert(kept, prettyProse(sent))
| |
| end
| |
| end
| |
| end
| |
| end
| |
| return table.concat(kept, '; ')
| |
| end
| |
| | |
| local function containsIgnoreCase(haystack, needle)
| |
| return mw.ustring.find(mw.ustring.lower(haystack), mw.ustring.lower(needle), 1, true) ~= nil
| |
| end | | end |
|
| |
|
| local function displayName(frame) | | local function displayName(frame) |
| local first = prettyNamePart(parentArg(frame, 'first')) | | local first = parentArg(frame, 'first') |
| local middle = prettyNamePart(parentArg(frame, 'middle')) | | local middle = parentArg(frame, 'middle') |
| local surname = prettyNamePart(parentArg(frame, 'surname')) | | local surname = parentArg(frame, 'surname') |
| local suffix = prettyNamePart(parentArg(frame, 'suffix')) | | local suffix = parentArg(frame, 'suffix') |
| local parts = {} | | local parts = {} |
| if first ~= '' then | | if first ~= '' then |
| Line 393: |
Line 53: |
| end | | end |
|
| |
|
| local function classLinkList(raw, withPrefix)
| | function p.displayName(frame) |
| local out = {} | | return displayName(frame) |
| for part in mw.text.gsplit(raw, ';', true) do
| |
| part = trim(part)
| |
| if part ~= '' then
| |
| if withPrefix then
| |
| table.insert(out, string.format('[[Class %s]]', part))
| |
| else
| |
| table.insert(out, string.format('[[Class %s|%s]]', part, part))
| |
| end
| |
| end
| |
| end
| |
| return out
| |
| end | | end |
|
| |
|
| local function teamLinkList(raw, pagePrefix, label)
| | function p.classLinks(frame) |
| | local raw = parentArg(frame, 'class_number') |
| local out = {} | | local out = {} |
| for part in mw.text.gsplit(raw, ';', true) do | | for part in mw.text.gsplit(raw, ';', true) do |
| part = trim(part)
| |
| part = mw.ustring.gsub(part, '[#<>%[%]|{}]', '')
| |
| part = trim(part) | | part = trim(part) |
| if part ~= '' then | | if part ~= '' then |
| table.insert(out, string.format('[[Team %s%s|%s %s]]', pagePrefix, part, label, part)) | | table.insert(out, string.format('[[Class %s|%s]]', part, part)) |
| end | | end |
| end | | end |
| Line 421: |
Line 69: |
| end | | end |
|
| |
|
| local function assignmentLink(raw)
| | function p.lead(frame) |
| raw = trim(raw)
| | local name = displayName(frame) |
| if raw == '' then
| | local surname = parentArg(frame, 'surname') |
| return ''
| | if surname == '' then |
| end
| | surname = name |
| raw = mw.ustring.gsub(raw, '[#<>%[%]|{}]', '')
| |
| raw = trim(raw) | |
| if raw == '' then | |
| return ''
| |
| end
| |
| return string.format('[[Assignment %s|%s]]', raw, raw)
| |
| end
| |
| | |
| local function addHeader(tbl, text)
| |
| tbl:tag('tr'):tag('th')
| |
| :attr('colspan', '2')
| |
| :addClass('infobox-header')
| |
| :wikitext(text)
| |
| end
| |
| | |
| local function addRow(tbl, label, value, dataClass)
| |
| if trim(value) == '' then | |
| return
| |
| end
| |
| local tr = tbl:tag('tr')
| |
| tr:tag('th'):addClass('infobox-label'):wikitext(label)
| |
| local td = tr:tag('td'):addClass('infobox-data')
| |
| if dataClass and dataClass ~= '' then
| |
| td:addClass(dataClass) | |
| end
| |
| td:wikitext(value)
| |
| end
| |
| | |
| local function yearOnly(s)
| |
| s = trim(s)
| |
| if s == '' or s == '?' then
| |
| return ''
| |
| end | | end |
| local year = mw.ustring.match(s, '(%d%d%d%d)') | | local birth = parentArg(frame, 'birth_year') |
| if year then | | local death = parentArg(frame, 'death_year') |
| return year
| | local dates = '' |
| end
| |
| return ''
| |
| end
| |
| | |
| local RANK_MAP = { | |
| ['PVT'] = 'Private',
| |
| ['PVTE'] = 'Private',
| |
| ['PRIVATE'] = 'Private',
| |
| ['PFC'] = 'Private First Class',
| |
| ['P F C'] = 'Private First Class',
| |
| ['PRIVATE FIRST CLASS'] = 'Private First Class',
| |
| ['CPL'] = 'Corporal',
| |
| ['CORPORAL'] = 'Corporal',
| |
| ['T/5'] = 'Technician Fifth Grade',
| |
| ['TEC5'] = 'Technician Fifth Grade',
| |
| ['TEC 5'] = 'Technician Fifth Grade',
| |
| ['T5'] = 'Technician Fifth Grade',
| |
| ['TECH 5'] = 'Technician Fifth Grade',
| |
| ['SGT'] = 'Sergeant',
| |
| ['SERGEANT'] = 'Sergeant',
| |
| ['T/4'] = 'Technician Fourth Grade',
| |
| ['TEC4'] = 'Technician Fourth Grade',
| |
| ['TEC 4'] = 'Technician Fourth Grade',
| |
| ['T4'] = 'Technician Fourth Grade',
| |
| ['TECH 4'] = 'Technician Fourth Grade',
| |
| ['S/SGT'] = 'Staff Sergeant',
| |
| ['SSGT'] = 'Staff Sergeant',
| |
| ['S SGT'] = 'Staff Sergeant',
| |
| ['STAFF SERGEANT'] = 'Staff Sergeant',
| |
| ['T/3'] = 'Technician Third Grade',
| |
| ['TEC3'] = 'Technician Third Grade',
| |
| ['TEC 3'] = 'Technician Third Grade',
| |
| ['T3'] = 'Technician Third Grade',
| |
| ['TECH 3'] = 'Technician Third Grade',
| |
| ['T/SGT'] = 'Technical Sergeant',
| |
| ['TSGT'] = 'Technical Sergeant',
| |
| ['T SGT'] = 'Technical Sergeant',
| |
| ['TECHNICAL SERGEANT'] = 'Technical Sergeant',
| |
| ['1ST SGT'] = 'First Sergeant',
| |
| ['1SGT'] = 'First Sergeant',
| |
| ['FIRST SERGEANT'] = 'First Sergeant',
| |
| ['M/SGT'] = 'Master Sergeant',
| |
| ['MSGT'] = 'Master Sergeant',
| |
| ['MASTER SERGEANT'] = 'Master Sergeant',
| |
| ['WO'] = 'Warrant Officer',
| |
| ['WOJG'] = 'Warrant Officer',
| |
| ['WARRANT OFFICER'] = 'Warrant Officer',
| |
| ['CWO'] = 'Chief Warrant Officer',
| |
| ['2ND LT'] = 'Second Lieutenant',
| |
| ['2D LT'] = 'Second Lieutenant',
| |
| ['2LT'] = 'Second Lieutenant',
| |
| ['SECOND LIEUTENANT'] = 'Second Lieutenant',
| |
| ['1ST LT'] = 'First Lieutenant',
| |
| ['1LT'] = 'First Lieutenant',
| |
| ['FIRST LIEUTENANT'] = 'First Lieutenant',
| |
| ['LT'] = 'Lieutenant',
| |
| ['LIEUTENANT'] = 'Lieutenant',
| |
| ['CAPT'] = 'Captain',
| |
| ['CPT'] = 'Captain',
| |
| ['CAPTAIN'] = 'Captain',
| |
| ['MAJ'] = 'Major',
| |
| ['MAJOR'] = 'Major',
| |
| ['LT COL'] = 'Lieutenant Colonel',
| |
| ['LTCOL'] = 'Lieutenant Colonel',
| |
| ['LTC'] = 'Lieutenant Colonel',
| |
| ['LIEUTENANT COLONEL'] = 'Lieutenant Colonel',
| |
| ['COL'] = 'Colonel',
| |
| ['COLONEL'] = 'Colonel',
| |
| ['BRIG GEN'] = 'Brigadier General',
| |
| ['BG'] = 'Brigadier General',
| |
| ['BRIGADIER GENERAL'] = 'Brigadier General',
| |
| ['MAJ GEN'] = 'Major General',
| |
| ['MG'] = 'Major General',
| |
| ['MAJOR GENERAL'] = 'Major General',
| |
| ['LT GEN'] = 'Lieutenant General',
| |
| ['LIEUTENANT GENERAL'] = 'Lieutenant General',
| |
| ['GEN'] = 'General',
| |
| ['GENERAL'] = 'General',
| |
| ['TECH'] = 'Technician',
| |
| ['TEC'] = 'Technician',
| |
| }
| |
| | |
| local function expandRank(raw)
| |
| raw = trim(raw)
| |
| if raw == '' then
| |
| return ''
| |
| end
| |
| local key = mw.ustring.upper(raw) | |
| key = mw.ustring.gsub(key, '%.', '')
| |
| key = mw.ustring.gsub(key, '%s+', ' ')
| |
| key = trim(key)
| |
| return RANK_MAP[key] or raw
| |
| end
| |
| | |
| local function lifespan(birth, death)
| |
| birth = yearOnly(birth)
| |
| death = yearOnly(death)
| |
| if birth ~= '' and death ~= '' then | | if birth ~= '' and death ~= '' then |
| return ' (' .. birth .. '–' .. death .. ')' | | dates = string.format(' (%s ? %s)', birth, death) |
| end
| | elseif birth ~= '' then |
| if birth ~= '' then | | dates = string.format(' (born %s)', birth) |
| return ' (born ' .. birth .. ')' | | elseif death ~= '' then |
| | dates = string.format(' (died %s)', death) |
| end | | end |
| if death ~= '' then
| |
| return ' (died ' .. death .. ')'
| |
| end
| |
| return ''
| |
| end
| |
|
| |
|
| local function preferredRank(frame)
| | local rank = parentArg(frame, 'rank_final') |
| local rank = expandRank(parentArg(frame, 'rank_final')) | |
| if rank == '' then | | if rank == '' then |
| rank = expandRank(parentArg(frame, 'class_rank')) | | rank = parentArg(frame, 'class_rank') |
| end | | end |
| return rank
| |
| end
| |
|
| |
|
| function p.displayName(frame)
| | local role = 'was a United States Army' |
| return displayName(frame) | | if rank ~= '' then |
| end
| | role = role .. ' ' .. rank |
| | end |
| | role = role .. ' soldier' |
|
| |
|
| function p.classLinks(frame)
| | local classRaw = parentArg(frame, 'class_number') |
| return table.concat(classLinkList(parentArg(frame, 'class_number'), false), ', ') | | local classLinks = {} |
| end
| | for part in mw.text.gsplit(classRaw, ';', true) do |
| | | part = trim(part) |
| function p.infobox(frame)
| | if part ~= '' then |
| local name = displayName(frame) | | table.insert(classLinks, string.format('[[Class %s]]', part)) |
| local tbl = mw.html.create('table') | |
| tbl:addClass('infobox'):addClass('vcard'):addClass('soldier-infobox')
| |
| | |
| tbl:tag('tr'):tag('th')
| |
| :attr('colspan', '2')
| |
| :addClass('infobox-above fn')
| |
| :wikitext(name)
| |
| | |
| local photo = parentArg(frame, 'photo')
| |
| if photo ~= '' then
| |
| local size = parentArg(frame, 'image_size') | |
| if size == '' then | |
| size = '220px' | |
| end
| |
| local alt = parentArg(frame, 'alt')
| |
| if alt == '' then
| |
| alt = name
| |
| end
| |
| local td = tbl:tag('tr'):tag('td')
| |
| :attr('colspan', '2')
| |
| :addClass('infobox-image')
| |
| td:wikitext(string.format('[[File:%s|%s|alt=%s]]', photo, size, alt))
| |
| local caption = parentArg(frame, 'caption')
| |
| if caption ~= '' then
| |
| td:tag('div'):addClass('infobox-caption'):wikitext(caption)
| |
| end | | end |
| end | | end |
| | | if #classLinks == 1 then |
| local alias = prettyNamePart(parentArg(frame, 'alias')) | | role = role .. ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1] |
| local birth = yearOnly(parentArg(frame, 'birth_year'))
| | elseif #classLinks > 1 then |
| local death = yearOnly(parentArg(frame, 'death_year'))
| | role = role .. ' who trained at [[Camp Ritchie]], Maryland, in classes ' .. table.concat(classLinks, ', ') |
| local nativity = parentArg(frame, 'nativity')
| | else |
| local religion = parentArg(frame, 'religion')
| | role = role .. ' associated with Camp Ritchie, Maryland' |
| local marital = prettyProse(parentArg(frame, 'marital')) | |
| local education = prettyProse(parentArg(frame, 'education'))
| |
| local occupation = prettyProse(parentArg(frame, 'occupation'))
| |
| local state = prettyPlace(parentArg(frame, 'state'))
| |
| | |
| if alias ~= '' or birth ~= '' or death ~= '' or nativity ~= ''
| |
| or religion ~= '' or marital ~= '' or education ~= ''
| |
| or occupation ~= '' or state ~= '' then | |
| addHeader(tbl, 'Personal details')
| |
| end
| |
| | |
| addRow(tbl, 'Nickname', alias, 'nickname')
| |
| addRow(tbl, 'Born', birth)
| |
| addRow(tbl, 'Nativity', nativity)
| |
| addRow(tbl, 'Died', death)
| |
| addRow(tbl, 'Religion', religion)
| |
| addRow(tbl, 'Spouse / marital', marital)
| |
| addRow(tbl, 'Education', education) | |
| addRow(tbl, 'Occupation', occupation)
| |
| if state ~= '' then
| |
| addRow(tbl, 'State', state)
| |
| end | | end |
|
| |
|
| addHeader(tbl, 'Military service')
| | local sentences = { |
| addRow(tbl, 'Allegiance', 'United States')
| | string.format("'''%s'''%s %s.", name, dates, role) |
| local branch = parentArg(frame, 'class_branch') | | } |
| if branch == '' then
| |
| branch = 'United States Army'
| |
| end
| |
| addRow(tbl, 'Branch', branch)
| |
| addRow(tbl, 'ASN', parentArg(frame, 'asn'), 'serial') | |
|
| |
|
| local rankFinal = expandRank(parentArg(frame, 'rank_final')) | | local enlist = parentArg(frame, 'enlistment_place') |
| local classRank = expandRank(parentArg(frame, 'class_rank')) | | local state = parentArg(frame, 'state') |
| if rankFinal ~= '' and classRank ~= '' and classRank ~= rankFinal then | | if enlist ~= '' then |
| addRow(tbl, 'Rank', rankFinal) | | local place = titleCase(enlist) |
| addRow(tbl, 'Rank at Ritchie', classRank)
| | if state ~= '' then |
| else
| | place = place .. ', ' .. titleCase(state) |
| local rank = rankFinal
| |
| if rank == '' then | |
| rank = classRank | |
| end | | end |
| addRow(tbl, 'Rank', rank) | | table.insert(sentences, surname .. ' enlisted at ' .. place .. '.') |
| | elseif state ~= '' then |
| | table.insert(sentences, 'Records list ' .. titleCase(state) .. ' as the state of enlistment or residence.') |
| end | | end |
|
| |
|
| local classRaw = parentArg(frame, 'class_number') | | local assignment = parentArg(frame, 'assignment') |
| local classBits = classLinkList(classRaw, false) | | if assignment ~= '' then |
| if #classBits > 0 then
| | table.insert(sentences, surname .. ' was assigned to ' .. assignment .. '.') |
| addRow(tbl, 'Camp Ritchie', 'Class ' .. table.concat(classBits, ', ')) | |
| end | | end |
| addRow(tbl, 'Section', parentArg(frame, 'class_section'))
| |
| addRow(tbl, 'Other class', parentArg(frame, 'other_class'))
| |
|
| |
|
| local enlist = prettyPlace(parentArg(frame, 'enlistment_place')) | | local ipw = {} |
| if enlist ~= '' then | | local ge = parentArg(frame, 'ipw_ge') |
| addRow(tbl, 'Enlisted', enlist) | | local it = parentArg(frame, 'ipw_it') |
| | if ge ~= '' then |
| | table.insert(ipw, 'German-language IPW team ' .. ge) |
| end | | end |
| addRow(tbl, 'Assignment', assignmentLink(parentArg(frame, 'assignment')))
| | if it ~= '' then |
| addRow(tbl, 'Unit / division', prettyProse(parentArg(frame, 'division')))
| | table.insert(ipw, 'Italian-language IPW team ' .. it) |
| addRow(tbl, 'IPW (German)', teamLinkList(parentArg(frame, 'ipw_ge'), 'IPW ', 'IPW'))
| |
| addRow(tbl, 'IPW (Italian)', teamLinkList(parentArg(frame, 'ipw_it'), 'IPW Italian ', 'IPW Italian'))
| |
| addRow(tbl, 'Special', prettyProse(parentArg(frame, 'special')))
| |
| addRow(tbl, 'LOC', parentArg(frame, 'loc'))
| |
| addRow(tbl, 'Arrived', parentArg(frame, 'date_arrive'))
| |
| addRow(tbl, 'Departed', parentArg(frame, 'date_depart'))
| |
| addRow(tbl, 'Certificate', parentArg(frame, 'certificate'))
| |
| | |
| return tostring(tbl)
| |
| end
| |
| | |
| function p.lead(frame)
| |
| local name = displayName(frame)
| |
| local rank = preferredRank(frame)
| |
| local role = 'United States Army soldier'
| |
| if rank ~= '' then | |
| role = 'United States Army ' .. rank | |
| end | | end |
| | | if #ipw > 0 then |
| local classLinks = classLinkList(parentArg(frame, 'class_number'), true)
| | table.insert(sentences, 'Interrogation duty included ' .. table.concat(ipw, ' and ') .. '.') |
| local trained
| |
| if #classLinks == 1 then | |
| trained = ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1] | |
| elseif #classLinks == 2 then
| |
| trained = ' who trained at [[Camp Ritchie]], Maryland, in ' .. classLinks[1] .. ' and ' .. classLinks[2]
| |
| elseif #classLinks > 2 then
| |
| trained = ' who trained at [[Camp Ritchie]], Maryland, in '
| |
| .. table.concat(classLinks, ', ', 1, #classLinks - 1)
| |
| .. ', and ' .. classLinks[#classLinks]
| |
| else
| |
| trained = ' associated with Camp Ritchie, Maryland'
| |
| end | | end |
|
| |
|
| local lead = string.format( | | table.insert(sentences, 'Add a fuller biography, a photograph, and sources below.') |
| "'''%s'''%s was a %s%s.",
| |
| name,
| |
| lifespan(parentArg(frame, 'birth_year'), parentArg(frame, 'death_year')),
| |
| role,
| |
| trained
| |
| )
| |
| local who = prettyNamePart(parentArg(frame, 'first'))
| |
| if who == '' then
| |
| who = prettyNamePart(parentArg(frame, 'surname'))
| |
| end
| |
| if who == '' then
| |
| who = 'He'
| |
| end
| |
| local enlist = prettyPlace(parentArg(frame, 'enlistment_place'))
| |
| if enlist ~= '' then
| |
| lead = lead .. ' ' .. who .. ' enlisted at ' .. enlist .. '.'
| |
| end
| |
| return lead
| |
| end
| |
|
| |
|
| function p.researchNotes(frame)
| | return table.concat(sentences, ' ') |
| local title = mw.title.getCurrentTitle()
| |
| if not title or not title.getContent then
| |
| return ''
| |
| end
| |
| local ok, content = pcall(function()
| |
| return title:getContent()
| |
| end)
| |
| if not ok or not content or content == '' then
| |
| return ''
| |
| end
| |
| local startPos = mw.ustring.find(content, '== Research notes ==', 1, true)
| |
| if not startPos then | |
| return ''
| |
| end
| |
| local after = mw.ustring.sub(content, startPos + 20)
| |
| local nextHead = mw.ustring.find(after, '\n== ', 1, true)
| |
| local section = after
| |
| if nextHead then
| |
| section = mw.ustring.sub(after, 1, nextHead - 1)
| |
| end
| |
| local items = {}
| |
| for line in mw.text.gsplit(section, '\n', true) do
| |
| line = trim(line)
| |
| if mw.ustring.sub(line, 1, 2) == '* ' then
| |
| local note = sanitizeNote(mw.ustring.sub(line, 3))
| |
| if note ~= '' then
| |
| table.insert(items, note)
| |
| end
| |
| end
| |
| end
| |
| if #items == 0 then
| |
| return ''
| |
| end
| |
| local wrap = mw.html.create('div')
| |
| wrap:addClass('soldier-research-notes')
| |
| wrap:tag('div'):addClass('soldier-research-notes-heading'):wikitext('Research notes')
| |
| local ul = wrap:tag('ul')
| |
| for _, note in ipairs(items) do
| |
| ul:tag('li'):wikitext(note)
| |
| end
| |
| return tostring(wrap)
| |
| end | | end |
|
| |
|
| return p | | return p |
|
| |