Module:Player: Difference between revisions
From eSportsAmaze
More actions
Esportsamaze (talk | contribs) No edit summary |
No edit summary |
||
| (19 intermediate revisions by 2 users not shown) | |||
| Line 20: | Line 20: | ||
local hasSocials = false | local hasSocials = false | ||
local platforms = { | local platforms = { | ||
{arg='instagram', file='Icon_instagram.png'}, | {arg='instagram', file='Icon_instagram.png', base='https://www.instagram.com/'}, | ||
{arg='twitter', file='Icon_twitter.png'}, | {arg='twitter', file='Icon_twitter.png', base='https://twitter.com/'}, | ||
{arg='youtube', file='Icon_youtube.png'}, | {arg='youtube', file='Icon_youtube.png', base='https://www.youtube.com/'}, | ||
{arg='discord', file='Icon_discord.png'}, | {arg='discord', file='Icon_discord.png', base='https://discord.gg/'}, | ||
{arg='facebook', file='Icon_facebook.png'} | {arg='facebook', file='Icon_facebook.png', base='https://www.facebook.com/'} | ||
} | } | ||
for _, p in ipairs(platforms) do | for _, p in ipairs(platforms) do | ||
local val = args[p.arg] | |||
if val and val ~= "" then | |||
hasSocials = true | hasSocials = true | ||
container:wikitext('[[File:' .. p.file .. '|24px|link=' .. | local link | ||
if val:match("^https?://") then | |||
link = val | |||
else | |||
link = p.base .. val | |||
end | |||
container:wikitext('[[File:' .. p.file .. '|24px|link=' .. link .. '|class=social-img]]') | |||
end | end | ||
end | end | ||
| Line 35: | Line 42: | ||
end | end | ||
-- | -- Rank Lookup | ||
local function getKraftonRank( | local function getKraftonRank(fullPageName, displayName) | ||
local | local sqlFull = fullPageName:gsub("'", "\\'") | ||
if #results > 0 then return "#" .. results[1].rank else return "Unranked" end | local sqlShort = displayName:gsub("'", "\\'") | ||
local whereClause = string.format("(BINARY name = '%s' OR BINARY name = '%s') AND type='Player'",sqlFull,sqlShort) | |||
local results = cargo.query("Krafton_Rankings", "rank", { where = whereClause, limit = 1 }) | |||
if results and #results > 0 then | |||
return "#" .. results[1].rank | |||
else | |||
return "Unranked" | |||
end | |||
end | end | ||
-- ============================================================ | -- ============================================================ | ||
-- MAIN 1: PLAYER INFOBOX ( | -- MAIN 1: PLAYER INFOBOX (WITH EARNINGS BREAKDOWN) | ||
-- ============================================================ | -- ============================================================ | ||
function p.infobox(frame) | function p.infobox(frame) | ||
local args = frame:getParent().args | local args = frame:getParent().args | ||
-- | |||
local | -- Variables | ||
local fullPageName = mw.title.getCurrentTitle().text | |||
local displayName = args.id or mw.title.getCurrentTitle().subpageText | |||
local image = args.image or "" | local image = args.image or "" | ||
| Line 54: | Line 70: | ||
-- 1. Header | -- 1. Header | ||
root:tag('div'):addClass('fib-header') | root:tag('div'):addClass('fib-header') | ||
:tag('div'):addClass('fib-title'):wikitext( | :tag('div'):addClass('fib-title'):wikitext(displayName) | ||
-- 2. Image | -- 2. Image | ||
| Line 61: | Line 77: | ||
imgContainer:wikitext('[[File:' .. image .. '|250px]]') | imgContainer:wikitext('[[File:' .. image .. '|250px]]') | ||
else | else | ||
imgContainer:wikitext('[[File:Player_Placeholder.png|200px|link=]]') | imgContainer:wikitext('[[File:Player_Placeholder.png|200px|link=]]') | ||
end | end | ||
-- 3. | -- 3. EARNINGS CALCULATION (SEPARATED) | ||
local individualEarnings = 0 | |||
local | local teamEarnings = 0 | ||
local sqlNameFull = fullPageName:gsub("'", "\\'") | |||
local sqlNameShort = displayName:gsub("'", "\\'") | |||
-- PART A: INDIVIDUAL AWARDS | |||
if cargo and cargo.query then | if cargo and cargo.query then | ||
local | local pWhere = string.format("(player = '%s' OR player = '%s')", sqlNameFull, sqlNameShort) | ||
if | local pResults = cargo.query("PrizeMoney", "SUM(prize)=total", { where = pWhere }) | ||
if pResults and #pResults > 0 and pResults[1].total then | |||
individualEarnings = (tonumber(pResults[1].total) or 0) | |||
end | end | ||
end | end | ||
-- PART B: TEAM WINNINGS | |||
if cargo and cargo.query then | |||
local rosterTable = "Tournament_Teams" | |||
local rosterFields = "tournament, team" | |||
local rosterWhere = string.format( | |||
"p1='%s' OR p1='%s' OR p2='%s' OR p2='%s' OR p3='%s' OR p3='%s' OR p4='%s' OR p4='%s' OR p5='%s' OR p5='%s' OR p6='%s' OR p6='%s'", | |||
sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, | |||
sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort | |||
) | |||
local participation = cargo.query(rosterTable, rosterFields, { where = rosterWhere, limit=500 }) | |||
if participation and #participation > 0 then | |||
local prizeConditions = {} | |||
for _, row in ipairs(participation) do | |||
if row.tournament and row.team then | |||
table.insert(prizeConditions, string.format("(tournament='%s' AND team='%s')", row.tournament:gsub("'", "\\'"), row.team:gsub("'", "\\'"))) | |||
end | |||
end | |||
if #prizeConditions > 0 then | |||
local complexWhere = "(" .. table.concat(prizeConditions, " OR ") .. ") AND (player='' OR player IS NULL)" | |||
local teamPrizes = cargo.query("PrizeMoney", "SUM(prize)=team_total", { where = complexWhere }) | |||
if teamPrizes and #teamPrizes > 0 and teamPrizes[1].team_total then | |||
teamEarnings = (tonumber(teamPrizes[1].team_total) or 0) | |||
end | |||
end | |||
end | |||
end | |||
-- Calculate Total | |||
local totalEarnings = individualEarnings + teamEarnings | |||
-- 4. Status & Rank Grid | -- 4. Status & Rank Grid | ||
local statusColor = "#333" | local statusColor = "#333" | ||
| Line 87: | Line 141: | ||
local grid1 = root:tag('div'):addClass('fib-grid') | local grid1 = root:tag('div'):addClass('fib-grid') | ||
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Status'):done():tag('div'):addClass('fib-value-sm'):css('color', statusColor):wikitext(statusText):done() | grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Status'):done():tag('div'):addClass('fib-value-sm'):css('color', statusColor):wikitext(statusText):done() | ||
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Krafton Rank'):done():tag('div'):addClass('fib-value-sm'):wikitext( | |||
local rankVal = getKraftonRank(fullPageName, displayName) | |||
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Krafton Rank'):done():tag('div'):addClass('fib-value-sm'):wikitext(rankVal):done() | |||
-- 5. Role & Nation Grid | -- 5. Role & Nation Grid | ||
| Line 94: | Line 150: | ||
grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Role'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.role or 'Player'):done() | grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Role'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.role or 'Player'):done() | ||
-- 6. Earnings (Highlight) | -- 6. Earnings (Highlight WITH BREAKDOWN) | ||
if | if totalEarnings > 0 then | ||
root:tag('div'):addClass('fib-prize') | local prizeBox = root:tag('div'):addClass('fib-prize') | ||
-- Main Total | |||
prizeBox:tag('div'):addClass('fib-label-sm'):wikitext('Approx. Earnings'):done() | |||
prizeBox:tag('div'):addClass('fib-prize-val'):wikitext(formatCurrency(totalEarnings)):done() | |||
-- Breakdown Sub-Section | |||
local breakdown = prizeBox:tag('div') | |||
:css('display', 'flex') | |||
:css('justify-content', 'space-between') | |||
:css('margin-top', '8px') | |||
:css('padding-top', '6px') | |||
:css('border-top', '1px solid rgba(0,0,0,0.08)') | |||
-- Team Winnings (Left) | |||
local tDiv = breakdown:tag('div'):css('text-align', 'left') | |||
tDiv:tag('div'):css('font-size', '0.65em'):css('text-transform', 'uppercase'):css('opacity', '0.7'):wikitext('Team'):done() | |||
tDiv:tag('div'):css('font-size', '0.85em'):css('font-weight', '600'):wikitext(formatCurrency(teamEarnings)):done() | |||
-- Individual Winnings (Right) | |||
local iDiv = breakdown:tag('div'):css('text-align', 'right') | |||
iDiv:tag('div'):css('font-size', '0.65em'):css('text-transform', 'uppercase'):css('opacity', '0.7'):wikitext('Individual'):done() | |||
iDiv:tag('div'):css('font-size', '0.85em'):css('font-weight', '600'):wikitext(formatCurrency(individualEarnings)):done() | |||
end | end | ||
| Line 112: | Line 188: | ||
addRow('Born', args.birth_date) | addRow('Born', args.birth_date) | ||
if args.current_team then | if args.current_team then | ||
addRow('Current Team', '[[' .. args.current_team .. ']]') | addRow('Current Team', '[[' .. args.current_team .. ']]') | ||
end | end | ||
addRow('Game', args.game or "BGMI") | addRow('Game', args.game or "BGMI") | ||
-- 8. Team History | -- 8. Team History | ||
local history = cargo.query("Player_Former_Teams", "team, join_date, leave_date", { | local history = cargo.query("Player_Former_Teams", "team, join_date, leave_date", { | ||
where = "player_id = '" .. | where = "player_id = '" .. fullPageName:gsub("'", "\\'") .. "'", | ||
orderBy = "join_date DESC", | orderBy = "join_date DESC", | ||
limit = 10 | limit = 10 | ||
| Line 126: | Line 200: | ||
if #history > 0 then | if #history > 0 then | ||
list:tag('div'):addClass('fib-header'):css('font-size','0. | list:tag('div'):addClass('fib-header'):css('font-size','0.95em'):css('padding','10px'):css('margin-top','15px'):css('border-radius','6px'):wikitext('Team History') | ||
local histTable = list:tag('table'):css('width','100%'):css('font-size','0. | local histTable = list:tag('table'):css('width','100%'):css('font-size','0.9em'):css('border-collapse','collapse'):css('margin-top','5px') | ||
for _, hRow in ipairs(history) do | for _, hRow in ipairs(history) do | ||
local tr = histTable:tag('tr'):css('border-bottom','1px solid # | local tr = histTable:tag('tr'):css('border-bottom','1px solid #e2e8f0') | ||
tr:tag('td'):css('padding','8px 4px'):css('font-weight','600'):wikitext('[[' .. hRow.team .. ']]') | |||
tr:tag('td'):css('padding','4px | |||
local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now') | local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now') | ||
tr:tag('td'):css('text-align','right'):css('color','#64748b'):wikitext(dates) | tr:tag('td'):css('text-align','right'):css('padding','8px 4px'):css('color','#64748b'):wikitext(dates) | ||
end | |||
else | |||
-- Fallback check for short name | |||
local historyShort = cargo.query("Player_Former_Teams", "team, join_date, leave_date", { | |||
where = "player_id = '" .. displayName:gsub("'", "\\'") .. "'", | |||
orderBy = "join_date DESC", | |||
limit = 10 | |||
}) | |||
if #historyShort > 0 then | |||
list:tag('div'):addClass('fib-header'):css('font-size','0.95em'):css('padding','10px'):css('margin-top','15px'):css('border-radius','6px'):wikitext('Team History') | |||
local histTable = list:tag('table'):css('width','100%'):css('font-size','0.9em'):css('border-collapse','collapse'):css('margin-top','5px') | |||
for _, hRow in ipairs(historyShort) do | |||
local tr = histTable:tag('tr'):css('border-bottom','1px solid #e2e8f0') | |||
tr:tag('td'):css('padding','8px 4px'):css('font-weight','600'):wikitext('[[' .. hRow.team .. ']]') | |||
local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now') | |||
tr:tag('td'):css('text-align','right'):css('padding','8px 4px'):css('color','#64748b'):wikitext(dates) | |||
end | |||
end | end | ||
end | end | ||
| Line 146: | Line 235: | ||
-- ============================================================ | -- ============================================================ | ||
-- MAIN 2: FORMER PLAYERS TABLE | -- MAIN 2: FORMER PLAYERS TABLE | ||
-- ============================================================ | -- ============================================================ | ||
function p.formerPlayers(frame) | function p.formerPlayers(frame) | ||
| Line 158: | Line 247: | ||
}) | }) | ||
local root = html.create('table'):addClass('wikitable flat-table sortable'):css('width','100%') | local root = html.create('table'):addClass('wikitable flat-table sortable'):css('width','100%') | ||
local header = root:tag('tr') | local header = root:tag('tr') | ||
Latest revision as of 12:11, 31 January 2026
Documentation for this module may be created at Module:Player/doc
local p = {}
local cargo = mw.ext.cargo
local html = mw.html
-- ============================================================
-- HELPER FUNCTIONS
-- ============================================================
-- Currency Formatter
local function formatCurrency(amount)
if not amount then return "0" end
local n = tonumber(amount) or 0
local formatted = tostring(n):reverse():gsub("(%d%d%d)(%d%d%d)","%1,%2"):reverse()
return '<span class="indian-currency">₹ ' .. formatted .. '</span>'
end
-- Social Icons
local function getSocials(args)
local container = html.create('div'):addClass('fib-socials')
local hasSocials = false
local platforms = {
{arg='instagram', file='Icon_instagram.png', base='https://www.instagram.com/'},
{arg='twitter', file='Icon_twitter.png', base='https://twitter.com/'},
{arg='youtube', file='Icon_youtube.png', base='https://www.youtube.com/'},
{arg='discord', file='Icon_discord.png', base='https://discord.gg/'},
{arg='facebook', file='Icon_facebook.png', base='https://www.facebook.com/'}
}
for _, p in ipairs(platforms) do
local val = args[p.arg]
if val and val ~= "" then
hasSocials = true
local link
if val:match("^https?://") then
link = val
else
link = p.base .. val
end
container:wikitext('[[File:' .. p.file .. '|24px|link=' .. link .. '|class=social-img]]')
end
end
if hasSocials then return tostring(container) else return "" end
end
-- Rank Lookup
local function getKraftonRank(fullPageName, displayName)
local sqlFull = fullPageName:gsub("'", "\\'")
local sqlShort = displayName:gsub("'", "\\'")
local whereClause = string.format("(BINARY name = '%s' OR BINARY name = '%s') AND type='Player'",sqlFull,sqlShort)
local results = cargo.query("Krafton_Rankings", "rank", { where = whereClause, limit = 1 })
if results and #results > 0 then
return "#" .. results[1].rank
else
return "Unranked"
end
end
-- ============================================================
-- MAIN 1: PLAYER INFOBOX (WITH EARNINGS BREAKDOWN)
-- ============================================================
function p.infobox(frame)
local args = frame:getParent().args
-- Variables
local fullPageName = mw.title.getCurrentTitle().text
local displayName = args.id or mw.title.getCurrentTitle().subpageText
local image = args.image or ""
local root = html.create('div'):addClass('flat-infobox')
-- 1. Header
root:tag('div'):addClass('fib-header')
:tag('div'):addClass('fib-title'):wikitext(displayName)
-- 2. Image
local imgContainer = root:tag('div'):addClass('fib-image')
if image ~= "" then
imgContainer:wikitext('[[File:' .. image .. '|250px]]')
else
imgContainer:wikitext('[[File:Player_Placeholder.png|200px|link=]]')
end
-- 3. EARNINGS CALCULATION (SEPARATED)
local individualEarnings = 0
local teamEarnings = 0
local sqlNameFull = fullPageName:gsub("'", "\\'")
local sqlNameShort = displayName:gsub("'", "\\'")
-- PART A: INDIVIDUAL AWARDS
if cargo and cargo.query then
local pWhere = string.format("(player = '%s' OR player = '%s')", sqlNameFull, sqlNameShort)
local pResults = cargo.query("PrizeMoney", "SUM(prize)=total", { where = pWhere })
if pResults and #pResults > 0 and pResults[1].total then
individualEarnings = (tonumber(pResults[1].total) or 0)
end
end
-- PART B: TEAM WINNINGS
if cargo and cargo.query then
local rosterTable = "Tournament_Teams"
local rosterFields = "tournament, team"
local rosterWhere = string.format(
"p1='%s' OR p1='%s' OR p2='%s' OR p2='%s' OR p3='%s' OR p3='%s' OR p4='%s' OR p4='%s' OR p5='%s' OR p5='%s' OR p6='%s' OR p6='%s'",
sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort,
sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort, sqlNameFull, sqlNameShort
)
local participation = cargo.query(rosterTable, rosterFields, { where = rosterWhere, limit=500 })
if participation and #participation > 0 then
local prizeConditions = {}
for _, row in ipairs(participation) do
if row.tournament and row.team then
table.insert(prizeConditions, string.format("(tournament='%s' AND team='%s')", row.tournament:gsub("'", "\\'"), row.team:gsub("'", "\\'")))
end
end
if #prizeConditions > 0 then
local complexWhere = "(" .. table.concat(prizeConditions, " OR ") .. ") AND (player='' OR player IS NULL)"
local teamPrizes = cargo.query("PrizeMoney", "SUM(prize)=team_total", { where = complexWhere })
if teamPrizes and #teamPrizes > 0 and teamPrizes[1].team_total then
teamEarnings = (tonumber(teamPrizes[1].team_total) or 0)
end
end
end
end
-- Calculate Total
local totalEarnings = individualEarnings + teamEarnings
-- 4. Status & Rank Grid
local statusColor = "#333"
local statusText = args.status or "Active"
if args.status then
local s = args.status:lower()
if s == "active" then statusColor = "#16a34a"
elseif s == "inactive" or s == "banned" or s == "retired" then statusColor = "#dc2626"
end
end
local grid1 = root:tag('div'):addClass('fib-grid')
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Status'):done():tag('div'):addClass('fib-value-sm'):css('color', statusColor):wikitext(statusText):done()
local rankVal = getKraftonRank(fullPageName, displayName)
grid1:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Krafton Rank'):done():tag('div'):addClass('fib-value-sm'):wikitext(rankVal):done()
-- 5. Role & Nation Grid
local grid2 = root:tag('div'):addClass('fib-grid')
grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Nationality'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.nationality or 'India'):done()
grid2:tag('div'):addClass('fib-cell'):tag('div'):addClass('fib-label-sm'):wikitext('Role'):done():tag('div'):addClass('fib-value-sm'):wikitext(args.role or 'Player'):done()
-- 6. Earnings (Highlight WITH BREAKDOWN)
if totalEarnings > 0 then
local prizeBox = root:tag('div'):addClass('fib-prize')
-- Main Total
prizeBox:tag('div'):addClass('fib-label-sm'):wikitext('Approx. Earnings'):done()
prizeBox:tag('div'):addClass('fib-prize-val'):wikitext(formatCurrency(totalEarnings)):done()
-- Breakdown Sub-Section
local breakdown = prizeBox:tag('div')
:css('display', 'flex')
:css('justify-content', 'space-between')
:css('margin-top', '8px')
:css('padding-top', '6px')
:css('border-top', '1px solid rgba(0,0,0,0.08)')
-- Team Winnings (Left)
local tDiv = breakdown:tag('div'):css('text-align', 'left')
tDiv:tag('div'):css('font-size', '0.65em'):css('text-transform', 'uppercase'):css('opacity', '0.7'):wikitext('Team'):done()
tDiv:tag('div'):css('font-size', '0.85em'):css('font-weight', '600'):wikitext(formatCurrency(teamEarnings)):done()
-- Individual Winnings (Right)
local iDiv = breakdown:tag('div'):css('text-align', 'right')
iDiv:tag('div'):css('font-size', '0.65em'):css('text-transform', 'uppercase'):css('opacity', '0.7'):wikitext('Individual'):done()
iDiv:tag('div'):css('font-size', '0.85em'):css('font-weight', '600'):wikitext(formatCurrency(individualEarnings)):done()
end
-- 7. Info List
local list = root:tag('div'):addClass('fib-list')
local function addRow(label, value)
if value and value ~= "" then
list:tag('div'):addClass('fib-row'):tag('div'):addClass('fib-label'):wikitext(label):done():tag('div'):addClass('fib-data'):wikitext(value):done()
end
end
addRow('Real Name', args.real_name)
addRow('Born', args.birth_date)
if args.current_team then
addRow('Current Team', '[[' .. args.current_team .. ']]')
end
addRow('Game', args.game or "BGMI")
-- 8. Team History
local history = cargo.query("Player_Former_Teams", "team, join_date, leave_date", {
where = "player_id = '" .. fullPageName:gsub("'", "\\'") .. "'",
orderBy = "join_date DESC",
limit = 10
})
if #history > 0 then
list:tag('div'):addClass('fib-header'):css('font-size','0.95em'):css('padding','10px'):css('margin-top','15px'):css('border-radius','6px'):wikitext('Team History')
local histTable = list:tag('table'):css('width','100%'):css('font-size','0.9em'):css('border-collapse','collapse'):css('margin-top','5px')
for _, hRow in ipairs(history) do
local tr = histTable:tag('tr'):css('border-bottom','1px solid #e2e8f0')
tr:tag('td'):css('padding','8px 4px'):css('font-weight','600'):wikitext('[[' .. hRow.team .. ']]')
local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now')
tr:tag('td'):css('text-align','right'):css('padding','8px 4px'):css('color','#64748b'):wikitext(dates)
end
else
-- Fallback check for short name
local historyShort = cargo.query("Player_Former_Teams", "team, join_date, leave_date", {
where = "player_id = '" .. displayName:gsub("'", "\\'") .. "'",
orderBy = "join_date DESC",
limit = 10
})
if #historyShort > 0 then
list:tag('div'):addClass('fib-header'):css('font-size','0.95em'):css('padding','10px'):css('margin-top','15px'):css('border-radius','6px'):wikitext('Team History')
local histTable = list:tag('table'):css('width','100%'):css('font-size','0.9em'):css('border-collapse','collapse'):css('margin-top','5px')
for _, hRow in ipairs(historyShort) do
local tr = histTable:tag('tr'):css('border-bottom','1px solid #e2e8f0')
tr:tag('td'):css('padding','8px 4px'):css('font-weight','600'):wikitext('[[' .. hRow.team .. ']]')
local dates = (hRow.join_date and mw.getContentLanguage():formatDate('M y', hRow.join_date) or '?') .. ' – ' .. (hRow.leave_date and mw.getContentLanguage():formatDate('M y', hRow.leave_date) or 'Now')
tr:tag('td'):css('text-align','right'):css('padding','8px 4px'):css('color','#64748b'):wikitext(dates)
end
end
end
-- 9. Socials
root:wikitext(getSocials(args))
return tostring(root)
end
-- ============================================================
-- MAIN 2: FORMER PLAYERS TABLE
-- ============================================================
function p.formerPlayers(frame)
local args = frame:getParent().args
local team = args.team or mw.title.getCurrentTitle().text
local results = cargo.query("Player_Former_Teams, Players", "Player_Former_Teams.player_id=id, Players.real_name=Name, Player_Former_Teams.role=role, Player_Former_Teams.join_date=join_date, Player_Former_Teams.leave_date=leave_date", {
joinOn = "Player_Former_Teams.player_id = Players._pageName",
where = "Player_Former_Teams.team = '" .. team:gsub("'", "\\'") .. "' AND Player_Former_Teams.leave_date != ''",
orderBy = "Player_Former_Teams.leave_date DESC"
})
local root = html.create('table'):addClass('wikitable flat-table sortable'):css('width','100%')
local header = root:tag('tr')
header:tag('th'):wikitext('ID'); header:tag('th'):wikitext('Name'); header:tag('th'):wikitext('Role'); header:tag('th'):wikitext('Duration')
if #results > 0 then
for _, row in ipairs(results) do
local tr = root:tag('tr')
tr:tag('td'):css('font-weight','bold'):wikitext('[[' .. row.id .. ']]')
tr:tag('td'):wikitext(row.Name)
tr:tag('td'):wikitext(row.role)
local range = (row.join_date and mw.getContentLanguage():formatDate('M Y', row.join_date) or '?') .. ' – ' .. (row.leave_date and mw.getContentLanguage():formatDate('M Y', row.leave_date) or '?')
tr:tag('td'):attr('data-sort-value', row.leave_date):wikitext(range)
end
else
return '<div style="font-style:italic; color:#64748b; padding:10px;">No former players found for this team.</div>'
end
return tostring(root)
end
return p