Module:NLLDivisionStanding explained

-- This module implements .

local yesno = require('Module:Yesno')

--------------------------------------------------------------------------------- Helper functions-------------------------------------------------------------------------------

local function abbr(shortForm, longForm) return tostring(mw.html.create('abbr') :attr('title', longForm) :wikitext(shortForm) )end

--------------------------------------------------------------------------------- Team class-------------------------------------------------------------------------------

local Team = Team.__index = Team

Team.stringFields =

Team.numberFields =

function Team.new(options) options = options or local self = setmetatable(Team) for i, field in ipairs(Team.stringFields) do self[field] = options[field] end for i, field in ipairs(Team.numberFields) do self[field] = tonumber(options[field]) end return selfend

function Team:getPosition return tostring(self.pos) or '--'end

function Team:getShortName return self.shortend

function Team:getName return self.nameend

function Team:getLink local name = self:getName local link = self.link if link and name then return string.format('%s', link, name) elseif link then return string.format('%s', link) else return name endend

function Team:makeDisplayName local ret = self:getLink if not ret then return nil end local clinches = -- The numerical syntax here is a hangover from the wikitext template -- which used #expr hacks to calculate the number of clinches if self.clinch_playoff

1 then table.insert(clinches, 'x') end if self.clinch_playoff

2 then table.insert(clinches, 'c') end if self.clinch_division

1 then table.insert(clinches, 'y') end if self.clinch_best_record

1 then table.insert(clinches, 'z') end if clinches[1] then ret = string.format("%s  - %s", ret, table.concat(clinches)) end return retend

function Team:getHomeWins return self.home_win or 0end

function Team:getHomeLosses return self.home_loss or 0end

function Team:getRoadWins return self.road_win or 0end

function Team:getRoadLosses return self.road_loss or 0end

function Team:getGamesPlayed return self:getHomeWins + self:getRoadWins + self:getHomeLosses + self:getRoadLossesend

function Team:getWins return self:getHomeWins + self:getRoadWinsend

function Team:getLosses return self:getHomeLosses + self:getRoadLossesend

function Team:_divideByGamesPlayed(val) local gp = self:getGamesPlayed if gp > 0 then -- avoid divide-by-zero error return val / gp else return 0 endend

function Team:getWinPercentage local percent = self:_divideByGamesPlayed(self:getWins) if percent > 1 then percent = 1 elseif percent < 0 then percent = 0 end local ret = string.format('%.3f', percent) if ret:sub(1, 1)

'0' then -- Use strings like .123 instead of 0.123 as that is how it's done -- in sports publications ret = ret:sub(2, -1) end return retend

function Team:getGamesBack(teamInFirst) local tifDiff = teamInFirst:getWins - teamInFirst:getLosses local selfDiff = self:getWins - self:getLosses return string.format('%.1f', (tifDiff - selfDiff) / 2)end

function Team:getHomeRecord return self:getHomeWins .. ' - ' .. self:getHomeLossesend

function Team:getRoadRecord return self:getRoadWins .. ' - ' .. self:getRoadLossesend

function Team:getGoalsScored return self.gf or 0end

function Team:getGoalsAllowed return self.ga or 0end

function Team:getDifferential local diff = self:getGoalsScored - self:getGoalsAllowed if diff > 0 then return '+' .. tostring(diff) else return '−' .. tostring(-diff) endend

function Team:getGameScoredAverage local avg = self:_divideByGamesPlayed(self:getGoalsScored) return string.format('%.2f', avg)end

function Team:getGameAllowedAverage local avg = self:_divideByGamesPlayed(self:getGoalsAllowed) return string.format('%.2f', avg)end

--------------------------------------------------------------------------------- DivisionStanding class-------------------------------------------------------------------------------

local DivisionStanding = DivisionStanding.__index = DivisionStanding

function DivisionStanding.new(args) local self = setmetatable(DivisionStanding)

-- Set template-wide arguments self.division = args.division self.conference = args.conference self.team = args.team self.hideLegend = yesno(args.hideLegend, false)

-- Separate args starting with "team" by team number. local teamArgs = for k, v in pairs(args) do if type(k)

'string' then local num, suffix = k:match('^team([1-9][0-9]*)_([a-z_]+)$') if num then num = tonumber(num) teamArgs[num] = teamArgs[num] or teamArgs[num][suffix] = v end end end

-- Make the team objects self.teams = for num, t in pairs(teamArgs) do self.teams[num] = Team.new(t) end

-- Find the first-place team if it has been specified self.teamInFirst = tonumber(args.teamInFirst) if self.teamInFirst then self.teamInFirst = self.teams[self.teamInFirst] end

-- Compress the teams array, which at the moment may contain nils self.teams = (function (t) local nums, ret =, for num in pairs(t) do nums[#nums + 1] = num end table.sort(nums) for i, num in ipairs(nums) do ret[i] = t[num] end return ret end)(self.teams)

-- Assume the first-place team is the first team in the teams array if it -- was not specified earlier if not self.teamInFirst then self.teamInFirst = self.teams[1] end

return selfend

function DivisionStanding:__tostring local root = mw.html.create local tableRoot = root:tag('table') tableRoot :addClass('wikitable sortable') :css('width', '65%')

-- Caption if self.division then tableRoot:tag('caption') :wikitext(self.division) :wikitext(' Division') elseif self.conference then tableRoot:tag('caption') :wikitext(self.conference) :wikitext(' Conference') end

-- Headers local headerRow = tableRoot:tag('tr') local function addHeader(display, width, sort) headerRow:tag('th') :css('width', tostring(width) .. '%') :attr('data-sort-type', sort) :wikitext(display) end addHeader(abbr('P', 'Position'), 4, 'number') addHeader('Team', 38, 'text') addHeader('GP', 4, 'number') addHeader('W', 4, 'number') addHeader('L', 4, 'number') addHeader('PCT', 5, 'number') addHeader('GB', 5, 'number') addHeader('Home', 6, 'number') addHeader('Road', 6, 'number') addHeader('GF', 4, 'number') addHeader('GA', 4, 'number') addHeader(abbr('Diff', 'Differential'), 4, 'number') addHeader('GF/GP', 6, 'number') addHeader('GA/GP', 6, 'number')

-- Empty header row. This is purely to hold the up-down arrow icons added -- with the "sortable" class, which helps to keep the table width down. local emptyHeaderRow = tableRoot:tag('tr') emptyHeaderRow:tag('th'):tag('br',) for i = 1, 13 do emptyHeaderRow:tag('th') end

-- Rows local function addTeamCell(teamRow, val, align) teamRow:tag('td') :css('text-align', align) :wikitext(val) end for i, team in ipairs(self.teams) do if team:getLink then local teamRow = tableRoot:tag('tr') teamRow :css('text-align', 'center') :css('background-color', self.team and self.team

team:getShortName and '#ccffcc' or nil ) addTeamCell(teamRow, team:getPosition) addTeamCell(teamRow, team:makeDisplayName, 'left') addTeamCell(teamRow, team:getGamesPlayed) addTeamCell(teamRow, team:getWins) addTeamCell(teamRow, team:getLosses) addTeamCell(teamRow, team:getWinPercentage) addTeamCell(teamRow, team:getGamesBack(self.teamInFirst)) addTeamCell(teamRow, team:getHomeRecord) addTeamCell(teamRow, team:getRoadRecord) addTeamCell(teamRow, team:getGoalsScored) addTeamCell(teamRow, team:getGoalsAllowed) addTeamCell(teamRow, team:getDifferential) addTeamCell(teamRow, team:getGameScoredAverage) addTeamCell(teamRow, team:getGameAllowedAverage) end end

-- Legend if not self.hideLegend then local function makeLegend(key, val) return string.format("%s: %s", key, val) end root:newline root:tag('small') :wikitext(table.concat('; ')) :tag('br',):done :wikitext(table.concat('; ')) :tag('br',):done :wikitext(table.concat('; ')) end

return tostring(root)end

--------------------------------------------------------------------------------- Exports-------------------------------------------------------------------------------

local p =

function p._main(args) return tostring(DivisionStanding.new(args))end

function p.main(frame) local args = require('Module:Arguments').getArgs(frame,) return p._main(args)end

return p