-
Notifications
You must be signed in to change notification settings - Fork 72
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: standardize CountryRepresentation (#5252)
* feat(CountryRepresentation): standardize CountryRepresentation * some missing annos * as per review
- Loading branch information
Showing
1 changed file
with
190 additions
and
0 deletions.
There are no files selected for viewing
190 changes: 190 additions & 0 deletions
190
components/country_representation/commons/country_representation.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,190 @@ | ||
--- | ||
-- @Liquipedia | ||
-- wiki=commons | ||
-- page=Module:CountryRepresentation | ||
-- | ||
-- Please see https://github.com/Liquipedia/Lua-Modules to contribute | ||
-- | ||
|
||
local Arguments = require('Module:Arguments') | ||
local Array = require('Module:Array') | ||
local Class = require('Module:Class') | ||
local Flags = require('Module:Flags') | ||
local Logic = require('Module:Logic') | ||
local Lua = require('Module:Lua') | ||
local MathUtil = require('Module:MathUtil') | ||
local Page = require('Module:Page') | ||
local Table = require('Module:Table') | ||
|
||
local Condition = require('Module:Condition') | ||
local ConditionTree = Condition.Tree | ||
local ConditionNode = Condition.Node | ||
local Comparator = Condition.Comparator | ||
local BooleanOperator = Condition.BooleanOperator | ||
local ColumnName = Condition.ColumnName | ||
|
||
local Widgets = Lua.import('Module:Widget/All') | ||
local Td = Widgets.Td | ||
local Th = Widgets.Th | ||
local Tr = Widgets.Tr | ||
local DataTable = Widgets.DataTable | ||
|
||
local WidgetUtil = Lua.import('Module:Widget/Util') | ||
|
||
---@class CountryRepresentation | ||
---@operator call(table<string, any>): CountryRepresentation | ||
---@field config CountryRepresentationConfig | ||
---@field byCountry table<string, {page:string, displayName: string?}[]> | ||
---@field count integer | ||
local CountryRepresentation = Class.new(function(self, args) self:init(args) end) | ||
|
||
---@class CountryRepresentationConfig | ||
---@field tournaments string[] | ||
---@field showNoCountry boolean | ||
---@field staff boolean | ||
|
||
---@param frame Frame | ||
---@return Widget | ||
function CountryRepresentation.run(frame) | ||
local args = Arguments.getArgs(frame) | ||
return CountryRepresentation(args):fetchAndProcess():create() | ||
end | ||
|
||
---@param args table | ||
---@return self | ||
function CountryRepresentation:init(args) | ||
self.config = { | ||
showNoCountry = args.noCountry ~= 'hide' or not Logic.readBool(args.noCountry), --- todo: bot to bool ... | ||
staff = args.staff == 'show' or Logic.readBool(args.staff), --- todo: bot to bool ... | ||
tournaments = Array.map(Array.extractValues(Table.filterByKey(args, function(key) | ||
return key:sub(1, #'tournament') == 'tournament' | ||
end)), Page.pageifyLink), | ||
} | ||
|
||
if Logic.isEmpty(self.config.tournaments) then | ||
self.config.tournaments = {Page.pageifyLink(mw.title.getCurrentTitle().text)} | ||
end | ||
|
||
return self | ||
end | ||
|
||
---@return string | ||
function CountryRepresentation:_buildConditions() | ||
local conditions = ConditionTree(BooleanOperator.all):add{ | ||
ConditionNode(ColumnName('mode'), Comparator.neq, 'award_individual'), | ||
ConditionTree(BooleanOperator.any):add( | ||
Array.map(self.config.tournaments, function(page) | ||
return ConditionNode(ColumnName('pagename'), Comparator.eq, page) | ||
end) | ||
), | ||
} | ||
|
||
return conditions:toString() | ||
end | ||
|
||
---@return self | ||
function CountryRepresentation:fetchAndProcess() | ||
local queryResult = mw.ext.LiquipediaDB.lpdb('placement', { | ||
limit = 5000, | ||
offset = 0, | ||
conditions = self:_buildConditions(), | ||
query = 'opponentplayers', | ||
}) | ||
|
||
local count = 0 | ||
local cache = {} | ||
local byCountry = {} | ||
local handleEntry = function(prefix, players) | ||
local page = players[prefix] | ||
if Logic.isEmpty(page) or cache[page] then return end | ||
|
||
local flag = players[prefix .. 'flag'] | ||
if Logic.isEmpty(flag) and not self.config.showNoCountry then return end | ||
|
||
cache[page] = true | ||
count = count + 1 | ||
|
||
byCountry[flag or ''] = byCountry[flag or ''] or {} | ||
table.insert(byCountry[flag or ''], {page = page, displayName = players[prefix .. 'dn']}) | ||
end | ||
|
||
Array.forEach(queryResult, function(placement) | ||
local players = placement.opponentplayers or {} | ||
for prefix in Table.iter.pairsByPrefix(players, 'p') do | ||
handleEntry(prefix, players) | ||
end | ||
if not self.config.staff then return end | ||
for prefix in Table.iter.pairsByPrefix(players, 'c') do | ||
handleEntry(prefix, players) | ||
end | ||
end) | ||
|
||
-- sort the players alphabetically for each country | ||
for _, tbl in pairs(byCountry) do | ||
table.sort(tbl, function(player1, player2) | ||
return string.lower(player1.page) < string.lower(player2.page) | ||
end) | ||
end | ||
|
||
self.byCountry = byCountry | ||
self.count = count | ||
|
||
return self | ||
end | ||
|
||
---@return Widget | ||
function CountryRepresentation:create() | ||
local cache = {rank = 0, counter = 0, lastCount = 0} | ||
local rows = {} | ||
for country, players in Table.iter.spairs(self.byCountry, CountryRepresentation._sortCountries) do | ||
cache.counter = cache.counter + 1 | ||
if #players ~= cache.lastCount then | ||
cache.rank = cache.counter | ||
end | ||
cache.lastCount = #players | ||
table.insert(rows, Tr{ | ||
children = { | ||
Td{css = {['text-align'] = 'right'}, children = {cache.rank}}, | ||
Td{children = {Flags.Icon(country), ' ', country}}, | ||
Td{css = {['text-align'] = 'right'}, children = {self:_ratioDisplay(#players)}}, | ||
Td{children = {table.concat(Array.map(players, function(player) | ||
return Page.makeInternalLink({}, player.displayName or player.page, player.page) | ||
end), ', ')}}, | ||
} | ||
}) | ||
end | ||
|
||
local headerRow = Tr{ | ||
children = { | ||
Th{classes = {'unsortable'}, children = {'#'}}, | ||
Th{children = {'Country / Region'}}, | ||
Th{children = {'Representation'}}, | ||
Th{classes = {'unsortable'}, children = {'Players'}}, | ||
} | ||
} | ||
|
||
return DataTable{ | ||
classes = {'sortable'}, | ||
children = WidgetUtil.collect(headerRow, rows), | ||
} | ||
end | ||
|
||
---@param byCountry {page:string, displayName: string?}[] | ||
---@param country1 string | ||
---@param country2 string | ||
---@return boolean | ||
function CountryRepresentation._sortCountries(byCountry, country1, country2) | ||
if #byCountry[country1] ~= #byCountry[country2] then | ||
return #byCountry[country1] > #byCountry[country2] | ||
end | ||
return country1 < country2 | ||
end | ||
|
||
---@param numberOfPlayers integer | ||
---@return string | ||
function CountryRepresentation:_ratioDisplay(numberOfPlayers) | ||
local percentage = self.count == 0 and 0 or MathUtil.round(100 * numberOfPlayers / self.count, 0) | ||
return numberOfPlayers .. ' / ' .. self.count .. ' (' .. percentage .. '%)' | ||
end | ||
|
||
return CountryRepresentation |