Module:TeamHistoryAuto
From Liquipedia Commons Wiki
This module is used to generate a team history table within {{Infobox player}}. It utilises transfer data saved to LPDB via {{Transfer Row}}.
While every matching transfer is listed in the LUA logs, only those with a joindate are eventually displayed.
Parameters[edit]
|player=
- Player page name (default: subpage name of the current page)
|returnEmptyIfNoResults=
- (Optional) If no transfers are found the module will return an empty string/nil instead of an empty (not displayed) html table
|hiderole=
- (Optional) Disables the role display
|addlpdbdata=
- (Optional) Enables the team history storage in lpdb data points
|specialRoles=
- (Optional) If enabled transfers with empty
toteam
but special role asrole2
(Retired, Military) are also considered valid |cleanRoles=
- (Optional) Cleanes roles from invalid ones via a provided module.
|convertrole=
- (Optional) Converts transfer roles (via
Module:TeamHistoryAuto/role
) |iconModule=
- (Optional) Adds icons to transfers based on the content in linked module. If the wiki is using positions, this is usually
Module:PositionIcon/data
.
Examples[edit]
See also[edit]
- Template:Transfer Row Dota 2
- Template:Transfer Row Rainbow Six
- Template:Transfer Row League of Legends
The above documentation is transcluded from Module:TeamHistoryAuto/doc. (edit | history) Editors can experiment in this module's sandbox (create | mirror) and testcases (create) pages. Subpages of this module. |
--remaining issue: player joins/leaves same team with multiple roles on different dates (e.g. MarioMe LoL wiki) --[[things still not meeting code style for the git: - several spans etc created as strings - condition building could use some further cleanup - move remaining const stuff as const vars up top - make it a class so we can kick `_config` ]] local Array = require('Module:Array') local Class = require('Module:Class') local DateExt = require('Module:Date/Ext') local Logic = require('Module:Logic') local String = require('Module:StringUtils') local Table = require('Module:Table') local Team = require('Module:Team') local LANG = mw.language.getContentLanguage() local SPECIAL_ROLES = {'Retired', 'Retirement', 'Military'} local SPECIAL_ROLES_LOWER = Array.map(SPECIAL_ROLES, string.lower) local LOAN = 'Loan' local ONE_DAY = 86400 local _config local TeamHistoryAuto = {} function TeamHistoryAuto._results(args) return TeamHistoryAuto.results(args) end function TeamHistoryAuto.results(args) args = args or {} TeamHistoryAuto._readConfig(args) local transferList = TeamHistoryAuto._buildTransferList() -- imo we should make this the default in the future, but would need some adjusts in player infoboxes when checking for an empty one if _config.returnEmptyIfNoResults and Table.isEmpty(transferList) then return end local display = mw.html.create('table') :css('width', '100%') :css('text-align', 'left') for teamCount, transfer in ipairs(transferList) do display:node(TeamHistoryAuto._displayTransfer(transfer, teamCount)) end return tostring(display) end function TeamHistoryAuto._readConfig(args) _config = { showRole = not Logic.readBool(args.hiderole), player = (args.player or mw.title.getCurrentTitle().subpageText):gsub('^%l', string.upper), store = Logic.readBool(args.addlpdbdata), specialRoles = Logic.readBool(args.specialRoles), roleConvert = Logic.readBool(args.convertrole) and mw.loadData('Module:TeamHistoryAuto/role'), roleClean = args.cleanRoles and mw.loadData(args.cleanRoles), iconConvert = args.iconModule and mw.loadData(args.iconModule), returnEmptyIfNoResults = Logic.readBool(Logic.emptyOr(args.returnEmptyIfNoResults, true)), } end function TeamHistoryAuto._buildTransferList() local roleConditions = _config.specialRoles and (' OR ' .. table.concat(Array.map(SPECIAL_ROLES, function(role) return '[[role2::' .. role .. ']] OR [[role2::' .. role:lower() .. ']]' end), ' OR ')) or '' local transferData = mw.ext.LiquipediaDB.lpdb('transfer', { conditions = '[[player::' .. _config.player .. ']] AND ([[toteam::>]]' .. roleConditions .. ') AND [[date::>' .. DateExt.defaultDate .. ']]', order = 'date asc', limit = 5000, query = 'pagename, fromteam, toteam, role1, role2, date, extradata' }) --[[@as transfer[]?]] local transferList = {} -- Process transfer (team, role, join date) for _, transfer in ipairs(transferData or {}) do -- need it like this; can not insert directly, else we get errors in some edge cases local transferEntry = TeamHistoryAuto._processTransfer(transfer, transferList) end -- release transferData to free up memory transferData = nil for _, transfer in pairs(transferList) do if _config.roleClean then transfer.role = _config.roleClean[(transfer.role or ''):lower()] end TeamHistoryAuto._completeTransfer(transfer) end -- Sort table by joinDate/leaveDate table.sort(transferList, function(transfer1, transfer2) if transfer1.joinDate == transfer2.joinDate then if transfer1.role == LOAN and transfer2.role ~= LOAN then return false elseif transfer2.role == LOAN and transfer1.role ~=LOAN then return true end return (transfer1.leaveDate or '') < (transfer2.leaveDate or '') end return transfer1.joinDate < transfer2.joinDate end) return transferList end function TeamHistoryAuto._processTransfer(transfer, transferList) local extraData = transfer.extradata local transferDate = LANG:formatDate('Y-m-d', transfer.date) if String.isNotEmpty(extraData.toteamsec) then -- transfer includes multiple teams (Tl:Transfer_row |team2_2, |role2_2) if (extraData.toteamsec ~= transfer.fromteam or extraData.role2sec ~= transfer.role1) and (extraData.toteamsec ~= extraData.fromteamsec or extraData.role2sec ~= extraData.role1sec) then -- secondary transfer table.insert(transferList, { team = extraData.toteamsec, role = extraData.role2sec, position = extraData.icon2, joinDate = transferDate, joinDateDisplay = extraData.displaydate or transferDate, }) end if (transfer.toteam ~= transfer.fromteam or transfer.role2 ~= transfer.role1) and (transfer.toteam ~= extraData.fromteamsec or transfer.role2 ~= extraData.role1sec) then -- primary transfer table.insert(transferList, { team = transfer.toteam, role = transfer.role2, position = extraData.icon2, joinDate = transferDate, joinDateDisplay = extraData.displaydate or transferDate, }) end elseif transfer.toteam ~= extraData.fromteamsec or transfer.role2 ~= extraData.role1sec then -- classic transfer table.insert(transferList, { team = transfer.toteam, role = transfer.role2, position = extraData.icon2, joinDate = transferDate, joinDateDisplay = extraData.displaydate or transferDate, }) end end function TeamHistoryAuto._completeTransfer(transfer) local leaveTransfers = mw.ext.LiquipediaDB.lpdb('transfer', { conditions = TeamHistoryAuto._buildConditions(transfer), order = 'date asc', query = 'toteam, role2, date, extradata' }) for _, leaveTransfer in ipairs(leaveTransfers) do local extraData = leaveTransfer.extradata if (leaveTransfer.toteam ~= transfer.team or leaveTransfer.role2 ~= (transfer.role or '') or extraData.icon2 ~= transfer.position) and (extraData.toteamsec ~= transfer.team or extraData.role2sec ~= (transfer.role or '')) then transfer.leaveDate = LANG:formatDate('Y-m-d', leaveTransfer.date) transfer.leaveDateDisplay = extraData.displaydate or transfer.leaveDate break end end end function TeamHistoryAuto._buildConditions(transfer) local historicalNames = Team.queryHistoricalNames(transfer.team) local conditions = { '[[player::' .. _config.player .. ']]', '([[date::>' .. transfer.joinDate .. ']] OR [[date::' .. transfer.joinDate .. ']])' } if historicalNames then local fromCondition = Array.map(historicalNames, function(team) return '[[fromteam::' .. team .. ']]' end) fromCondition = '(' .. table.concat(fromCondition, ' OR ') .. ')' if transfer.role then fromCondition = fromCondition .. ' AND [[role1::' .. transfer.role .. ']]' elseif not _config.roleClean then fromCondition = fromCondition .. ' AND [[role1::]]' end local fromConditionSecondary = Array.map(historicalNames, function(team) return '[[extradata_fromteamsec::' .. team .. ']]' end) fromConditionSecondary = '(' .. table.concat(fromConditionSecondary, ' OR ') .. ')' if transfer.role then fromConditionSecondary = fromConditionSecondary .. ' AND [[extradata_role1sec::' .. transfer.role .. ']]' elseif not _config.roleClean then fromConditionSecondary = fromConditionSecondary .. ' AND [[extradata_role1sec::]]' end table.insert(conditions, '(' .. fromCondition .. ' OR ' .. fromConditionSecondary .. ')') elseif Table.includes(SPECIAL_ROLES_LOWER, (transfer.role or ''):lower()) then table.insert(conditions, '[[role1::' .. transfer.role .. ']] OR [[role1::' .. transfer.role:lower() .. ']]') end return table.concat(conditions, ' AND ') end function TeamHistoryAuto._buildLeaveDateDisplay(transfer) if transfer.leaveDateDisplay then return transfer.leaveDateDisplay end local lowerCasedRole = (transfer.role or ''):lower() if lowerCasedRole == 'Military' or not Table.includes(SPECIAL_ROLES_LOWER, (transfer.role or ''):lower()) then return '<span style="font-weight:bold;">Present</span>' end return '' end function TeamHistoryAuto._displayTransfer(transfer, teamCount) local leaveDateDisplay = TeamHistoryAuto._buildLeaveDateDisplay(transfer) local teamLink, teamText if String.isEmpty(transfer.team) and Table.includes(SPECIAL_ROLES_LOWER, (transfer.role or ''):lower()) then teamText = '<b>' .. transfer.role .. '</b>' transfer.role = nil transfer.position = nil elseif mw.ext.TeamTemplate.teamexists(transfer.team) then local leaveDateCleaned = TeamHistoryAuto._adjustDate(transfer.leaveDate) local teamData = mw.ext.TeamTemplate.raw(transfer.team, leaveDateCleaned --[[@as string]]) teamLink = teamData.page teamText = '[[' .. teamLink .. '|' .. TeamHistoryAuto._buildTeamDisplayName(teamData) .. ']]' else teamLink = transfer.team teamText = '[[' .. transfer.team .. ']]' end if _config.store and (teamLink or transfer.role) then TeamHistoryAuto._storeLpdbDatapoint(teamCount, teamLink, transfer.joinDate, transfer.leaveDate, transfer.role) end if String.isNotEmpty(transfer.role) then if _config.roleConvert then local splitRole = mw.text.split(transfer.role, ' ') -- If we don't get a match, look at just the last word, there may be a prefix beforehand. transfer.role = _config.roleConvert[transfer.role:lower()] or _config.roleConvert[splitRole[#splitRole]:lower()] or transfer.role end if transfer.role == LOAN then teamText = '› ' .. teamText end if _config.showRole then teamText = teamText .. '<span style="padding-left:3px; font-style:italic;">(' .. transfer.role .. ')</span>' end end local position = (transfer.position or ''):lower() local icon = _config.iconConvert and (_config.iconConvert[position] or _config.iconConvert['']) or nil return TeamHistoryAuto._printTransfer(transfer.joinDateDisplay, leaveDateDisplay, teamText, icon) end function TeamHistoryAuto._storeLpdbDatapoint(teamCount, teamLink, joinDate, leaveDate, playerRole) mw.ext.LiquipediaDB.lpdb_datapoint('Team_'..teamCount, { type = 'teamhistory', name = _config.player, information = teamLink, extradata = mw.ext.LiquipediaDB.lpdb_create_json({ joindate = joinDate, leavedate = leaveDate or '2999-01-01', teamcount = teamCount, role = playerRole, auto = 1, }) }) end function TeamHistoryAuto._printTransfer(joinDate, leaveDate, teamText, icon) leaveDate = Logic.isNotEmpty(leaveDate) and (' — ' .. leaveDate) or nil return mw.html.create('tr') :tag('td') :addClass('th-mono') :css('float', 'left') :css('width', '50%') :css('font-style', 'italic') :wikitext(joinDate) :wikitext(leaveDate) :done() :tag('td') :css('float', 'right') :css('width', '50%') :wikitext(icon and (icon .. ' ') or nil) :wikitext(teamText) :done() end -- earlier date for fromteam to account for rebrands function TeamHistoryAuto._adjustDate(date) if type(date) ~= 'string' or String.isEmpty(date) then return date end local year, month, day = date:match('(%d+)-(%d+)-(%d+)') date = os.time({day=day, month=month, year=year}) return os.date('%Y-%m-%d', date - ONE_DAY) end function TeamHistoryAuto._buildTeamDisplayName(teamData) local teamName = teamData.name if string.len(teamName) <= 17 then return teamName end teamName = teamData.bracketname or teamData.name if string.len(teamName) <= 17 then return teamName end return teamData.shortname or teamData.name end return Class.export(TeamHistoryAuto)