Module:Goalscorers/sandbox

require('strict');

local yesno = require('Module:Yesno')

local p = {}

local g = {} -- for parameters with global scope in this module

g.goalscorers = {} -- table where selected and sorted players will be place

g.args = {}

g.totalGoals = 0

local data = {} -- module subpage data -- require('Module:Goalscorers/data/UEFA Euro 2016 qualifying');

p.errorString = ""

function p.error_msg()

if p.errorString ~= "" then

return ''

-- '|_template='

.. p.errorString .. '';

end

end

-- data for goals scored held in module subpages, e.g. "Module:Goalscorers/data/UEFA Euro 2016 qualifying"

--[[ parameters containing data help in three tables

data.rounds = {} -- group, play-off

data.goalscorers = {} -- player, country, goals in each round)

data.owngoalscorers = {} -- player, country, goals in each round)

data.updated = {} -- date of latest update (month, day, year)

--]]

--[[ ############################ Parameter handing ###############################

p.getArgs() - gets arguments from frame (invoke) or parent frame (template)

]]

local function getArgs(frame)

local parents = mw.getCurrentFrame():getParent()

for k,v in pairs(parents.args) do

--check content

if v and v ~= "" then

g.args[k]=mw.text.trim(v) --parents.args[k]

end

end

for k,v in pairs(frame.args) do

--check content

if v and v ~= "" then

g.args[k]= mw.text.trim(v) --parents.args[k]

end

end

-- allow empty caption to blank default

--if parents.args['caption'] then templateArgs['caption'] = parents.args['caption'] end

end

--[[ ############################## Main function and other functions ######################

p.main() - simple output of the data in the module in list form

p.addIntroductorySentence() - add sentence on number of goals and matches, with goals per match

p.addFooterSentence() - add footnote

p.getNumberMatches()

p.owngoals() - get own goals (no longer used?)

p._owngoals() - core functionality for p.owngoals()

]]

function p.main(frame)

getArgs(frame)

local dataTarget = g.args[1] or g.args['data']

if dataTarget then

data = require('Module:Goalscorers/data/'.. dataTarget) --or 'UEFA Euro 2016 qualifying'

return p.useModuleData(frame) -- data on goals taken from module subpage

else

return p.useTemplateData(frame) -- data on goals/assists taken from template

end

end

function p.useModuleData(frame)

--p.goalscorers = {} -- table where selected and sorted players will be place

g.totalGoals = 0

local ok = p.selectGoalscorers() -- selected goalscorers meeting round and group criteris

if not ok then return p.error_msg() end

-- CHANGE: append own goals to list (data will now include goals and own goals (negative))

p.selectGoalscorers("OG")

p.sortGoalscorers() -- sort selected goalscorers by number of goal, then country

local outputString = p.addIntroductorySentence() .. p.outputGoalscorers(frame) .. p.addFooterSentence()

-- .. "" --TODO add intermediate heading?

-- .. p._owngoals(frame) -- output list of goalscorers

return p.error_msg() or outputString

end

function p.addIntroductorySentence() -- add introductory text

local totalGoalString = "A total of " .. g.totalGoals .. " goals were scored."

--There were [has been|have been|was|were] #GOALS goal(s) scored in #MATCHES match(s), for an average of #GOALS/#MATCHES per match.

local matches, dateUpdated = p.getNumberMatches()

local mdyFormat = yesno(g.args['mdy'])

local Date = require('Module:Date')._Date

local pluralGoals = "s"

local text1 = ""

if g.totalGoals == 1 then

pluralGoals = ""

if dateUpdated == 'complete' then text1 = "was" else text1 = "has been" end

else

if dateUpdated == 'complete' then text1 = "were" else text1 = "have been" end

end

local text = string.format("There %s %s goal%s scored", text1, mw.getLanguage('en'):formatNum(g.totalGoals), pluralGoals)

local pluralMatches = "es"

if matches==1 then pluralMatches = "" end

if matches then

local average = g.totalGoals/tonumber(matches)

local precision = 3 -- display d.dd (three significant disgits)

if average < 1 then precision = 2 end -- display 0.dd (thwo significant disgits)

average = tostring (average)

local pluralAverage = "s"

if tonumber(string.format("%.2f",average))==1 then pluralAverage = "" end

text = text .. string.format(" in %d match%s, for an average of %."..precision.."g goal%s per match", matches, pluralMatches, average, pluralAverage)

end

if dateUpdated == 'complete' or dateUpdated == "" then

text = text .. "."

else

local dateFormat = 'dmy' -- default

if data.params and data.params['date_format'] then dateFormat = data.params['date_format'] end -- from data module

if mdyFormat == true then dateFormat = "mdy" else

if mdyFormat == false then dateFormat = "dmy" end -- template param overrides

end

text = text .. " (as of " .. Date(dateUpdated):text(dateFormat) .. ")."

end

text = p.addAdditionHeaderText(text, dateUpdated) -- handles template parameters bold, further, extra

return text --totalGoalString

end

function p.addFooterSentence() -- add notes at bottom

local footerSentence = g.args['footer'] or ""

--footerSentence = "This is a footer sentence." -- test footer

if data.params then

local footer = data.params['footer'] or nil

if footer then

local frame = mw.getCurrentFrame()

local processed = frame:preprocess(footer)

if g.notes then

footerSentence = footerSentence .. processed

end

end

end

if footerSentence ~= "" then

footerSentence = '

' .. footerSentence .. '
'

end

return footerSentence

end

function p.getNumberMatches()

local matches = g.args['matches']

local dateUpdated = data.updated['date'] or "1700-01-01" --'complete' -- assume completed if missing

--local round = g.args['round'] or "all" -- round = all(empty)|group|playoffs

--local group = g.args['group'] or "all" -- group = all(empty), A,B,C etc

local round, group = p.getRoundAndGroup()

local allGroupGames = 0

local latestGroupDate = "1800-01-01"

if group and (round == "all" or group == "all") then -- count all the group games

for k,v in pairs(data.updated.group) do

allGroupGames = allGroupGames + v[1]

if v[2] ~= "complete" and v[2] > latestGroupDate then latestGroupDate = v[2] end -- update if later date

end

if latestGroupDate == "1800-01-01" then latestGroupDate = "complete" end -- no dates so must be complete

end

if group and (round == "all" and group ~= "all") then -- for totals of all rounds with only one group

allGroupGames = data.updated.group[group][1] -- number matches

latestGroupDate = data.updated.group[group][2] -- update date or completed

end

if round == "all" then -- all rounds and goals

matches=0

for k,v in pairs(data.updated) do

if k == "group" then

matches = matches + allGroupGames

if latestGroupDate ~= "complete" and latestGroupDate > dateUpdated then

dateUpdated = latestGroupDate -- update if later date

end

elseif p.validateRound(k) then

matches = matches + v[1]

if v[2] ~= "complete" and v[2] > dateUpdated then dateUpdated = v[2] end -- update if later date

end

end

elseif round == "group" then -- group round only

if group == "all" then

matches = allGroupGames

dateUpdated = latestGroupDate

else -- single group only

matches = data.updated.group[group][1] -- number matches

dateUpdated = data.updated.group[group][2] -- update date or completed

end

else -- any other round

matches = data.updated[round][1] -- number matches

dateUpdated = data.updated[round][2] -- update date or completed

end

if dateUpdated == "1700-01-01" then dateUpdated = "complete" end -- no dates so must be complete

return matches, dateUpdated

end

function p.owngoals(frame) -- need to check parameters if external call

getArgs(frame)

data = require('Module:Goalscorers/data/'.. g.args[1]) --or 'UEFA Euro 2016 qualifying'

local outputString = p._owngoals(frame)

return p.error_msg() or outputString

end

function p._owngoals(frame) -- internal call for own goals

--p.goalscorers = {} -- table where selected and sorted players will be place

p.selectGoalscorers("OG") -- selected goalscorers meeting round and group criteris

p.sortGoalscorers() -- sort selected goalscorers by number of goal, then country

return p.outputGoalscorers(frame, "OG") -- output list of goalscorers

end

function p.validateRound(round)

local validateRound = false

for k,v in pairs(data.rounds) do

if k == round then validateRound = true end -- data for this round exists

end

return validateRound

end

--[[ ############################## functions to select goalscorers ######################

p.selectGoalscorers() - select goals scoreers required for list (rounds, groups)

p.getRoundAndGroup()

p.getGoalsCol(round) - get column containing round data or first data column if round = all

(country, possibleGroup)

p.getGoals (u, player)

p.parseComment(comment)

p.getPlayer(u)

]]

--[[ p.selectGoalscorers()

- select players meeting round and group criteria from goalscoreres list

- gets goals and comments

]]

function p.selectGoalscorers(og)

local round, group = p.getRoundAndGroup()

if not round then return false end -- exit if no valid round

local goalMinimum = tonumber(g.args['minimum']) or -5 -- assume 5 own goals is maximum

local goalsCol = p.getGoalsCol(round) -- first column for goals

-- select players who have scored in rounds/groups requested

local goalscorerData = data.goalscorers

if og == "OG" then goalscorerData = data.owngoalscorers end

for k,v in pairs(goalscorerData) do

local goals, comment = 0, "" -- goals > 0 is the flag to include the player

local playerName, playerAlias = p.getPlayer(v[1]) -- player name

local goalsByRound, commentByRound = 0, ""

if round == "all" then -- goals in all rounds and all groups

for i = goalsCol, #v, 1 do

if group and group ~= "all" and i == p.getGoalsCol("group") and group ~= p.getGroup(v[2], v[3]) then

goalsByRound = 0

commentByRound = ""

else

goalsByRound, commentByRound = p.getGoals( v[i] , playerName)

end

goals = goals + goalsByRound --TODO use getGoals on round options

if commentByRound ~= "" then

if comment == "" then

comment = commentByRound

else

comment = comment .. "," .. commentByRound --TODO decide on comma or semi-colon

end

end

i = i+1

end

elseif round == "all2" and group ~= "all" then -- goals in all rounds but only from one group

--TODO code to go through all rounds but only include goals in specified group [TODO merge with above option]

--mw.addWarning( g.args[1] .. ":Mix:round=all and group=" .. group .. "/" .. p.getGroup(v[2], v[3] ) )

for i = goalsCol, #v, 1 do

if i == p.getGoalsCol("group") and group ~= p.getGroup(v[2], v[3]) then

goalsByRound = 0

commentByRound = ""

else

goalsByRound, commentByRound = p.getGoals( v[i] , playerName)

end

goals = goals + goalsByRound

if commentByRound ~= "" then

if comment == "" then

comment = commentByRound

else

comment = comment .. "," .. commentByRound --TODO decide on comma or semi-colon

end

end

i = i+1

end

elseif round == "group" then -- group round only

if group == p.getGroup(v[2], v[3]) then -- single group only

goals, comment = p.getGoals( v[goalsCol] , playerName)

elseif group == "all" then -- any group

goals, comment = p.getGoals( v[goalsCol] , playerName)

else

-- do nothing for other groups

end

--elseif round == "playoffs" then -- playoff round (redunant?)

-- goals = v[goalsCol]

else -- any other round

goals, comment = p.getGoals( v[goalsCol] , playerName) -- should also handle playoffs

end

if goals >= goalMinimum and goals ~= 0 then

if comment ~= "" then

if og == "OG" then

comment = ' (' .. p.sortComment(comment) .. ')'

else

comment = '' .. comment .. '' -- no parenthesis when using notes

end

end

if og == "OG" then goals = -goals end -- make owngoals negative numbers

g.goalscorers[#g.goalscorers+1] = { player=playerName, alias=playerAlias,

country=v[2],

goals=goals,

comment=p.parseComment(comment)}

--g.totalGoals = g.totalGoals + math.abs(goals) -- increment total goal counter

end

g.totalGoals = g.totalGoals + math.abs(goals) -- increment total goal counter

end

return true -- data collected for selected goalscorers

end

--[[ p.getRoundAndGroup()

]]

function p.getRoundAndGroup()

local round = g.args['round'] or "all" -- round = all(empty)|group|playoffs

local group = g.args['group'] or "all" -- group = all(empty), A,B,C etc

local validateRound = false

local validateGroupRound = false

for k,v in pairs(data.rounds) do

if k == round then validateRound = true end -- data for this round exists

if k == "group" then validateGroupRound = true end -- there is a group round

end

if validateRound == false and round ~= "all" then

local message = 'Invalid round "' .. round .. '" specified. No data found for that round. '

mw.addWarning( message )

p.errorString = p.errorString .. message

round = nil

end

if validateGroupRound == false then group = false end -- there is no group round

-- TODO add group error checking

-- Could merge with getGoalsCol() and also return goalsCol

return round, group

end

--[[ p.getGoalsCol(round)

- get column containing round data or first data column if round = "all"

- allows group column to be omitted from player table when group table provided

]]

function p.getGoalsCol(round)

local minimum = 1000

if round == "all" then -- if all need column of first round

for k,v in pairs(data.rounds) do

if v < minimum then minimum = v end

--return v -- return the first one [this seemed to work reliably, but sometimes table order is not as listed]

end

return minimum

end

if data.rounds and data.rounds[round] then

return data.rounds[round] -- get column containing goals for that round

else

return 4 -- an old default when no data.round (may not be necessary)

end

end

--[[ p.getGroup(country, possibleGroup)

- get group from group table or from player table

- possibleGroup is the column containing the Group (when no group table) or the first data column

]]

function p.getGroup(country, possibleGroup) -- row contain player name, country code, group if given, goals

if data.groups then

for k,v in pairs(data.groups) do -- iterate through the groups

--local = gotGroup = false

for j,u in pairs(v) do -- for each group

if u == country then

return k

end

end

end

return "no group found"

else

return possibleGroup -- no group table, so assume column three contains the group

end

end

--[[ get number of goals and any associated comment

the goals can be a single number (the usual case)

or as an option table (e.g. for own goals): { number of own goals, comma-delimited list of opponents }

- if the entry is a table, we want the first entry (a number) and the second (comment string)

- otherwise, if a number, we just want the number and an empty string

]]

function p.getGoals (u, player)

if type(u) == 'table' and type(u[1]) == 'number' then

return u[1], u[2] -- return number of goals, comment

elseif type(u) == 'number' then

return u, "" -- return number of goals, empty string

else

p.errorString = p.errorString .. " Invalid goals entry for player " .. player

return 0, ""

end

end

function p.parseComment(comment)

local frame = mw.getCurrentFrame()

-- we have something like "{{efn-ua|name=goals}}"

if string.find(comment, "efn" , 1 , true ) then -- if we have a comment with a note

g.notes = true -- set flag

end

return frame:preprocess(comment)

end

function p.getPlayer(u)

if type(u) == 'table' then

if type(u[1]) == 'string' and type(u[2]) == 'string' then

--[[if #u[2] >1 then

p.errorString = p.errorString .. "\n\nWe have u[1]=" .. u[1] .. " and u[2]=" .. u[2]

end]]

return u[1], u[2] -- return player name, player sorting alias

else

p.errorString = p.errorString .. " Invalid name entry for player " .. u[1] .. ", " .. u[2]

return "", "" --TODO errroer

end

elseif type(u) == 'string' then

return u, "" -- return player name

else

p.errorString = p.errorString .. " Invalid name entry for player " .. u or u[1] or "unknown"

return "", ""

end

end

--[[ ############################## functions to sort goalscorers ######################

p.preprocessSortName (name)

p.getPlayerSortName (playerName, sortName, countryName)

p.sortComment(comment)

p.getCountryName(country)

p.sortGoalscorers() -- the main sort function

]]

--[=[ function p.preprocessSortName()

stripp off wikitext and

force to lowercase

change special characters to standard letters

]=]

function p.preprocessSortName (name)

name = string.gsub(name, "%[%[", "") -- strip off and

name = string.gsub(name, "%]%]", "")

--name =string.lower(name) -- force lower case and return

name = mw.ustring.lower(name) -- use unicode function

local specialChars = { -- list of special characters and replacement pairs

{ "ı", "i" } , { "İ", "i" } , { "ß", "ss" },

{ "ý", "y" } , { "ř", "r" } , { "ő", "o" },

{ "é", "e" } , { "è", "e" } , { "þ", "th" },

{ "ē", "e" } , { "ņ", "n" } , { "č", "c" },

{ "ū", "u" } , { "ž", "z" } , { "æ", "ae" },

{ "å", "a" } , { "ø", "o" } , { "ą", "a" },

{ "ń", "n" } , { "ł", "l" } , { "ã", "a" },

{ "ș", "s" } , { "š", "s" } , { "í", "i" },

{ "á", "a" } , { "ä", "a" } , { "ć", "c" },

{ "ç", "c" } , { "ğ", "g" } , { "ö", "o" },

{ "ë", "e" } , { "ú", "u" } , { "ó", "o" },

{ "ð", "d" } , { "ü", "u" } , { "ű", "u" },

{ "ā", "a" } , { "ī", "i" } , { "đ", "d" },

{ "ă", "a" } , { "â", "a" } , { "ż", "z" },

{ "ț", "t" } , { "ş", "s" } , { "ś", "s" },

{ "ǎ", "a" } , { "ě", "e" } , { "ů", "u" },

{ "ĕ", "e" } , { "ñ", "n" } , { "ď", "d" },

{ "ï", "i" } , { "ź", "z" } , { "ô", "o" },

{ "ė", "e" } , { "ľ", "l" } , { "ģ", "g" },

{ "ļ", "l" } , { "ę", "e" } , { "ň", "n" },

{ "ò", "o" } , { "œ", "oe" }

}

for k,v in pairs(specialChars) do -- replace special characters from supplied list

name = string.gsub(name, v[1], v[2])

end

return name

end

--[[ return the name for sorting

return supplied alias name for sorting

otherwise

checks for pipe (redirect) and uses name after pipe

splits name into words

returns first name if only name (e.g. Nani)

otherwise returns name in format second_name [.. last name], firstname

]]

function p.getPlayerSortName (playerName, sortName, countryName)

--dewikify all names before sorting, also forces lowercase

playerName = p.preprocessSortName(playerName)

sortName = p.preprocessSortName(sortName)

if sortName ~= "" then -- if we have a sort name supplied

return sortName -- then return it

end

-- players from certain countries will use name in order supplied

local noSort = { "CAM", "CHN", "TPE", "MYA", "PRK", "KOR", "VIE" }

for k,v in pairs(noSort) do

if v == countryName then

return playerName

end

end

-- else work it out from the supplied player name

-- we don't want to test the name in a redirect, so get name after pipe if there is one

if string.find (playerName, "|") then -- test for redirect

local names = mw.text.split( playerName, "|")

playerName = names[2] -- get name after pipe

end

local names = mw.text.split( playerName, " ") -- we don't want to sort on first name

if #names == 1 then

return names[1] -- return name of single name player

else

-- we will assume the second name is the sort name e.g, Joe Bloggs, Jan van Bloggen

local name = names[2] -- set name to second name e.g. Bloggs or van

local i=3

while i <= #names do -- any addition names e.g. Bloggen

name= name .. names[i]

i=i+1

end

name = name .. ", " .. names[1] -- add first name e.g. Joe or Jan

return name -- sort on second name third name etc, first name

end

end

-- sort the list of countries alphabetically

function p.sortComment(comment)

local items = mw.text.split( comment, ",") -- split comma-delimited list

for k,v in pairs(items) do

items[k] = mw.text.trim(v) -- trim spaces and coe

end

table.sort(items, function(a,b) return a

local list = "against " -- construct the alphabetical list string

for i=1, #items do

local sep = ", " -- separator for comma-delimited list

if i==1 then sep = "" -- first word doesn't need comma

elseif i==#items then sep = " & " -- use "and" before last word

end

list = list .. sep .. items[i]

end

return list

end

function p.getCountryName(country)

if string.len(country) == 3 then -- if the country given as a three-letter code

local codes = require('Module:Goalscorers/data/Country codes')

for k,v in pairs(codes.alias) do

if v[1] == country then

return v[2]

end

end

else

return country -- return the country name as is

end

end

--[[ sort goalscorers by goals, country and name

the sort first sorts by number of goals

when these are equal, it sorts by country

when these are equal, it sorts by name

Note: the name sort is on the first name

- a split of the name and sort on the last name is possible

- however, this would be complicated by Dutch (e.g. Stefan de Vrij) and Spanish names

- would sort on second name be better

]]

function p.sortGoalscorers()

local sort_function = function( a,b )

if (a.goals > b.goals) then -- primary sort on 'goals' -> a before b

return true

elseif (a.goals < b.goals) then -- primary sort on 'goals' -> b before a

return false

else -- a.goals == b.goals -- primary sort tied,

--return a.country < b.country -- resolve with secondary sort on 'country'

local country_a = p.getCountryName(a.country) -- sort on name of country, not the code

local country_b = p.getCountryName(b.country)

if (country_a < country_b) then -- secondary sort on 'country'

return true

elseif (country_a > country_b) then -- secondary sort on 'country'

return false

else -- a.country == b.country -- secondary sort tied,

--return a.player < b.player --resolve with tertiary sort on 'player' name

local player_a = p.getPlayerSortName(a.player, a.alias, a.country) -- get player name for sorting

local player_b = p.getPlayerSortName(b.player, b.alias, b.country)

return player_a < player_b --

--[[]

--local test_a, test_b = a.player, b.player

-- we don't want to test the name in a redirect, so get name after pipe if there is one

if string.find (a.player, "|") then -- test for redirect

local names = mw.text.split( a.player, "|")

test_a = names[2] -- get name after pipe

end

if string.find (b.player, "|") then

local names = mw.text.split( b.player, "|")

test_b = names[2]

end

local names_a = mw.text.split( test_a, " ") -- we don't want to sort on first name

local names_b = mw.text.split( test_b, " ") -- so split names

if not names_a[2] then names_a[2] = test_a end -- for players with one name

if not names_b[2] then names_b[2] = test_b end

return names_a[2] < names_b[2] -- sort on second name

]]

end

end

end

table.sort(g.goalscorers, sort_function)

end

function p.tabulateGoalscorers(frame, og)

-- ==============output the lists of goalscorers by goal======================

local goalNumber = 1000

local maxRank = tonumber(g.args['maxrank'] or 10) -- limit list top ten or value in parameter maxrank

local rank = 1

local playerCount = 0

local rankCount = 0

local playerCells = ""

local firstplayerCell = ""

local tableString = '\n

class="wikitable"' -- start table

..'\n

' .. '\n!Rank !! Player !! Goals' -- add table headers

if g.args['header'] then tableString = tableString .. '\n|+ ' .. g.args['header'] end -- add header

for j,u in pairs(g.goalscorers) do -- run through sorted list of selected goalscorers

-- is the player active still?

local playerActive = false

if data.active_countries then

for k,v in pairs(data.active_countries) do

if v == u['country'] then

playerActive = true

break;

end

end

end

local _,roundStatus = p.getNumberMatches()

if roundStatus == "complete" then playerActive = false end -- overrides active_countries

-- wikitext for tablulated list

local goalscorerString = p.addLinkedIcon(frame, u['country']) -- linked flag icon

if playerActive and g.args['bold']~='no' then

goalscorerString = goalscorerString .. " " .. u['player'] .. ">" -- bolded name

else

goalscorerString = goalscorerString .. " " .. u['player'] -- name

end

goalscorerString = goalscorerString .. u['comment'] -- comment for o.g.

-- we have a goalscorer

playerCount = playerCount + 1

rankCount = rankCount + 1

if u['goals'] < goalNumber then -- player belongs to rowspan for new number of goals

-- need to generate code for the previous rowspan (if there is one)

-- then start the counts and player list for the new one

if playerCount == 1 then

firstplayerCell = '\n|' .. goalscorerString -- if first player in list just create cell and set goals

goalNumber = u['goals']

--rank = 1

rankCount = 0

else -- else generate previous rowspan

local rowSpan = rankCount

if playerCount >= maxRank * 1.5 then

firstplayerCell = '\n| style="font-style:italic;text-align:center;"|' .. rankCount .. " players"

playerCells = ""

rowSpan = 1

end

tableString = tableString .. '\n

\n| style="text-align:center;" rowspan="' .. rowSpan .. '"|' .. rank

--if rankCount > 1 then tableString = tableString .. "=" end -- adds equals when rank shared

tableString = tableString .. firstplayerCell

tableString = tableString .. '\n| style="text-align:center;" rowspan="' .. rowSpan .. '"|' .. goalNumber

tableString = tableString .. playerCells

rank = rank + rankCount

if rank > maxRank then break end -- limit list top ten or value in parameter

rankCount = 0

goalNumber = u['goals']

firstplayerCell = '\n|' .. goalscorerString -- set first player cell for next rowspan

playerCells = ""

end

else -- else another player with same number of goals

playerCells = playerCells .. '\n

' .. '\n|' .. goalscorerString -- add to player cell list

end

end -- reached end of list of goalscorers [for j,u loop]

-- if all scorers on one goal, tableString isn't updated in loop above (may need to generalise for other goal number)

if goalNumber == 1 and rankCount >= (10-1) then -- special case: long list of goalscorers with one goal; don't show if more than 10 players

firstplayerCell = '\n| style="font-style:italic;text-align:center;"|' .. (rankCount+1) .. " players" -- replace list with "x players" text

playerCells = "" -- clear multirow list of players on one goal

rankCount = 0 -- reset to get single rowspan in next section

end

if goalNumber == 1 and rank <= maxRank then

local rowSpan = rankCount + 1

tableString = tableString .. '\n

\n| style="text-align:center;" rowspan="' .. rowSpan .. '"|' .. rank

tableString = tableString .. firstplayerCell

tableString = tableString .. '\n| style="text-align:center;" rowspan="' .. rowSpan .. '"|' .. goalNumber

tableString = tableString .. playerCells

end

if tableString ~= "" then

tableString = tableString .. "\n

"

return tableString

else

return (" No goals matching requested criteria.")

end

end

function p.outputGoalscorers(frame, og) -- output list of goalscorers

if g.args['table'] then return p.tabulateGoalscorers(frame, og) end -- optional table output

local outputString = ""

if og == "OG" then end

-- ==============output the lists of goalscorers by goal======================

local goalNumber = 1000

--local goalMinimum = tonumber(templateArgs['minimum']) or 0

local listOpen = false -- flag for list started by template {{Div Col}}

for j,u in pairs(g.goalscorers) do -- run through sorted list of selected goalscorers

--if u['goals'] < goalMinimum then break end -- limit list to goals over a threshold (now handled in select goalscorers)

if u['goals'] < goalNumber then -- start new list of new number of goals

if listOpen then -- if an open list, close last list

outputString = outputString .. p.closeList(frame)

listOpen = false -- redundant as will be set true again

end

goalNumber = u['goals']

local goalString = " goal"

--if og == "OG" then

if goalNumber < 0 then

goalString = " own" .. goalString

end

if math.abs(u['goals']) ~= 1 then goalString = goalString .. "s" end

outputString = outputString .. "\n" .. math.abs(u['goals']) .. goalString .. "" -- list caption

outputString = outputString .. p.openList(frame,og) --start new list

listOpen = true

--goalNumber = u['goals']

end

-- is the player active still?

local playerActive = false

if data.active_countries then

for k,v in pairs(data.active_countries) do

if v == u['country'] then

playerActive = true

break;

end

end

end

local _,roundStatus = p.getNumberMatches()

if roundStatus == "complete" then playerActive = false end -- overrides active_countries

-- wikitext for bullet list

local goalscorerString = '\n*' .. p.addLinkedIcon(frame, u['country']) -- linked flag icon

if playerActive and g.args['bold']~='no' then

goalscorerString = goalscorerString .. " " .. u['player'] .. "" -- bolded name

else

goalscorerString = goalscorerString .. " " .. u['player'] -- name

end

goalscorerString = goalscorerString .. u['comment'] .. '' -- comment for o.g.

outputString = outputString .. goalscorerString -- .. " " .. tostring(u['goals'])

end -- reached end of list of goalscorers

if outputString ~= "" then

outputString = outputString .. p.closeList(frame)

return outputString

else

return (" No goals matching requested criteria.")

end

end

-- output icon linked to national team page

function p.addLinkedIcon(frame, country)

local icon = data.templates['flag_icon_linked'] -- fbicon etc set in data module

local level = data.templates['youth_level'] or "" -- parameter for youth level, ie under-21

-- equivalent to {{fbicon|country}}

local flagVariant = ""

if data.templates.flagvar and data.templates.flagvar[country] then

flagVariant = data.templates.flagvar[country]

end

if level ~= "" then

return frame:expandTemplate{ title = icon , args = { level, country, flagVariant } }

else

return frame:expandTemplate{ title = icon , args = { country, flagVariant } } -- flag icon

end

end

-- formatting of list under each number of goals

function p.openList(frame,og)

return mw.getCurrentFrame():extensionTag{

name = 'templatestyles', args = { src = 'Div col/styles.css' }

} .. '

' -- perhaps add "column-count:3;"" to limit max number of columns?

end

function p.closeList(frame)

return '

'

end

function p.firstToUpper(str)

return (str:gsub("^%l", string.upper))

end

-- handles parameters bold, further, extra

function p.addAdditionHeaderText(text, dateUpdated)

if g.args['inlineref'] then

text = text .. g.args['inlineref']

end

if g.args['bold'] and g.args['bold']~='no' then

text = text .. " Players highlighted in bold are still active in the competition."

end

if g.args['further'] then

if text ~= "" then text = text .. " " end

text = text .. g.args['further']

end

if g.args['extra'] then

text = text .. "\n\n" .. g.args['extra']

end

return text

end

-- count number of goals for data in template

function p.countGoals(list, number, totalGoals)

local split = mw.text.split( list, "\n", true ) -- split the list for number of goals scorers with N goals

local count = #split * math.abs(number) -- calculate number of goals (including own goals)

totalGoals = totalGoals + count

--mw.addWarning( "Entry: " .. list .. "[" .. count .. "]")

return totalGoals

end

--[[ use data supplied by template

]]

--function p.list(frame)

function p.useTemplateData(frame)

--getArgs(frame)

--[[ {{{#if:{{{assists|}}}||There

{{#if:{{{ongoing|}}}|{{#ifexpr:{{{goals}}}=1|has|have}} been

|{{#ifexpr:{{{goals}}}=1|was|were}}}} {{{goals}}}

{{#ifexpr:{{{goals}}}=1|goal|goals}} scored{{#if:{{{players|}}}| by {{{players}}}

{{#ifexpr:{{{players}}}=1|player|different players}}

{{#if:{{{own goals|}}}| (with {{{own goals}}} of them credited as {{#ifexpr:{{{own goals}}}=1|an own goal|own goals}})|}}|}} in {{{matches}}}

{{#ifexpr:{{{matches}}}=1|match|matches}}, for an average of {{#expr:{{{goals}}}/{{{matches}}} round 2}}

{{#ifexpr:({{{goals}}}/{{{matches}}} round 2)=1|goal|goals}} per match

{{#if:{{{updated|}}}| (as of {{{updated}}})}}.}}{{#if:{{{bold|}}}|{{#if:{{{assists|}}}|| }}

Players highlighted in bold are still active in the competition.

|}}{{#if:{{{further|}}}|{{#if:{{{assists|}}}|| }}{{{further}}}|}}

{{#if:{{{extra|}}}|{{{extra}}}{{clear}}|}}

--]]

local statNumber = g.args['goals'] or g.args['assists'] or 0

local matches = g.args['matches']

local statType = "goal"

if g.args['assists'] then statType = "assist" end

if g.args['clean sheets'] then statType = "clean sheet" end

local ongoing = g.args['ongoing']

local text1 = "There"

if g.args['lc'] then text1 = "there" end

local text2 = "were"

if ongoing then text2 = "have been" end

local updateString = ""

local averageString = ""

local goalPlural = "s" -- goal(s)

if g.args['goals'] and tonumber(g.args['goals']) == 1 then

goalPlural = ""

text2 = "was"

if ongoing then text2 = "has been" end

end

local matchPlural = "es" -- match(es)

if g.args['matches'] and tonumber(g.args['matches']) == 1 then matchPlural = "" end

-- auto version: string.format(" in %d match%s, for an average of %."..precision.."g goal%s per match", matches, pluralMatches, average, pluralAverage)

if g.args['goals'] and g.args['matches'] then

local averageGoals = g.args['goals']/g.args['matches']

local avGoalPlural = "s"

if averageGoals == 1 then avGoalPlural = "" end

averageString = string.format(" in %d match%s, for an average of %.3g goal%s per match", g.args['matches'], matchPlural, averageGoals, avGoalPlural)

end

if g.args['updated'] and g.args['updated'] ~= "complete" then

updateString = " (as of " ..g.args['updated'] .. ")"

end

local sep = "."

if g.args['sep'] then sep = g.args['sep'] end

local text = ""

if g.args['goals'] then

text = string.format("%s %s %d %s%s scored%s",

text1, text2, statNumber, statType, goalPlural, averageString..updateString..sep)

end

text = p.addAdditionHeaderText(text) -- handles template parameters bold, further, extra

--[[ {{#if:{{{30 goals|{{{30 assists|}}}}}}|30 {{#if:{{{assists|}}}|assists|goals}}

{{#if:{{{assists|}}}|{{{30 assists}}}|{{{30 goals}}}}}

|}}]]

local output = (text == "") and "" or "\n"

local number = 30

local totalGoals = 0

while number > -4 do -- for the each goals/assists

local entry = g.args[number .. ' goals'] or g.args[number .. ' goal']

or g.args[number .. ' assists'] or g.args[number .. ' assist']

or g.args[number .. ' clean sheets'] or g.args[number .. ' clean sheet']

if number < 0 then

entry = g.args[math.abs(number) .. ' own goals'] or g.args[math.abs(number) .. ' own goal']

statType = "own goal"

end

local plural = "s"

if number == 1 or number == -1 then plural = "" end

if entry then -- do we have goals/assists for this number

output = output .. "\n" .. tostring(math.abs(number)) .. " " .. statType .. plural .. "\n"

.. p.openList(frame) .. "\n" .. entry .. p.closeList(frame)

totalGoals = p.countGoals(entry, number, totalGoals)

end

number = number -1

end

if statType == "goal" or statType == "own goal" then

if g.args['goals'] and totalGoals ~= tonumber(g.args['goals']) then

mw.addWarning("WARNING. Mismatch between number of goals listed (" .. totalGoals .. ") and goals parameter (" .. g.args['goals'] .. ").")

end

end

--{{#if:{{{bottom|}}}|{{small|{{{bottom_text}}}}}

{{{bottom}}}
|}}{{#if:{{{source|}}}|{{smaller|Source: {{{source}}}}}|}}

local footerText = g.args['footer-text'] or g.args['bottom'] or ""

local footerHeading = g.args['footer-heading'] or g.args['bottom-text'] or ""

local footer = ""

if footerText ~= "" then

local heading = ""

if footerHeading ~= "" then

heading = '

' .. footerHeading .. '

'

end

footer = '\n' .. heading .. p.openList(frame) .. '\n' .. footerText .. p.closeList(frame)

end

--{{#if:{{{source|}}}|{{small|Source: {{{source}}}}}|}}

local source = g.args['source'] or ""

if source ~= "" then source = "Source: " .. source .. "" end

return text .. output .. footer .. source

end

return p