Module:Goalscorers
Appearance
From Wikipedia, the free encyclopedia
This template shows football (soccer) goalscorers, and is used on many soccer pages.
This module is rated as beta. It is considered ready for widespread use, but as it is still relatively new, it should be applied with some caution to ensure results are as expected.
Page extended-confirmed-protected This module is currently under extended confirmed protection.
Extended confirmed protection prevents edits from all unregistered editors and registered users with fewer than 30 days tenure and 500 edits. The policy on community use specifies that extended confirmed protection can be applied to combat disruption, if semi-protection has proven to be ineffective. Extended confirmed protection may also be applied to enforce arbitration sanctions. Please discuss any changes on the talk page; you may submit an edit request to ask for uncontroversial changes supported by consensus.
Extended confirmed protection prevents edits from all unregistered editors and registered users with fewer than 30 days tenure and 500 edits. The policy on community use specifies that extended confirmed protection can be applied to combat disruption, if semi-protection has proven to be ineffective. Extended confirmed protection may also be applied to enforce arbitration sanctions. Please discuss any changes on the talk page; you may submit an edit request to ask for uncontroversial changes supported by consensus.
Data subpages
- Goalscorers/data/1960 European Nations' Cup qualifying
- Goalscorers/data/1964 European Nations' Cup qualifying
- Goalscorers/data/1998 FIFA World Cup qualification (CONCACAF)
- Goalscorers/data/2002 FIFA World Cup qualification (CONCACAF)
- Goalscorers/data/2006 FIFA World Cup qualification (AFC)
- Goalscorers/data/2006 FIFA World Cup qualification (CONCACAF)
- Goalscorers/data/2020–21 UEFA Nations League
- Goalscorers/data/2022 FIFA World Cup qualification (AFC)
- Goalscorers/data/2022 FIFA World Cup qualification (CAF)
- Goalscorers/data/2022 FIFA World Cup qualification (CONCACAF)
- Goalscorers/data/2022 FIFA World Cup qualification (UEFA)
- Goalscorers/data/2022–23 UEFA Nations League
- Goalscorers/data/2022–23 UEFA Nations League/sandbox
- Goalscorers/data/2023 AFC Asian Cup qualification
- Goalscorers/data/2024–25 UEFA Nations League
- Goalscorers/data/2025 UEFA Women's Nations League
- Goalscorers/data/2026 AFC Women's Asian Cup
- Goalscorers/data/2026 CONCACAF W Championship
- Goalscorers/data/2026 FIFA World Cup qualification (AFC)
- Goalscorers/data/2026 FIFA World Cup qualification (CAF)
- Goalscorers/data/2026 FIFA World Cup qualification (CONCACAF)
- Goalscorers/data/2026 FIFA World Cup qualification (OFC)
- Goalscorers/data/2026 FIFA World Cup qualification (UEFA)
- Goalscorers/data/2026 Women's Africa Cup of Nations
- Goalscorers/data/2027 AFC Asian Cup qualification
- Goalscorers/data/2027 FIFA Women's World Cup qualification (UEFA)
- Goalscorers/data/Country codes
- Goalscorers/data/UEFA Euro 1968 qualifying
- Goalscorers/data/UEFA Euro 1972 qualifying
- Goalscorers/data/UEFA Euro 1976 qualifying
- Goalscorers/data/UEFA Euro 1980 qualifying
- Goalscorers/data/UEFA Euro 1984 qualifying
- Goalscorers/data/UEFA Euro 1988 qualifying
- Goalscorers/data/UEFA Euro 1992 qualifying
- Goalscorers/data/UEFA Euro 1996 qualifying
- Goalscorers/data/UEFA Euro 2000 qualifying
- Goalscorers/data/UEFA Euro 2004 qualifying
- Goalscorers/data/UEFA Euro 2008 qualifying
- Goalscorers/data/UEFA Euro 2012 qualifying
- Goalscorers/data/UEFA Euro 2016 qualifying
- Goalscorers/data/UEFA Euro 2020 qualifying
- Goalscorers/data/UEFA Euro 2024 qualifying
- Goalscorers/data/doc
- Goalscorers/data/test competition
Usage
{{#invoke:Goalscorers|main}}
Used by template {{goalscorers }}.
The above documentation is transcluded from Module:Goalscorers/doc. (edit | history)
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Subpages of this module.
Editors can experiment in this module's sandbox (edit | diff) and testcases (create) pages.
Subpages of this module.
require('strict'); localyesno=require('Module:Yesno') localp={} localg={}-- for parameters with global scope in this module g.goalscorers={}-- table where selected and sorted players will be place g.args={} g.totalGoals=0 localdata={}-- module subpage data -- require('Module:Goalscorers/data/UEFA Euro 2016 qualifying'); p.errorString="" functionp.error_msg() ifp.errorString~=""then return'<span style="font-size:100%" class="error">' -- '<code style="color:inherit;border:inherit;padding:inherit;">|_template=</code>' ..p.errorString..'</span>'; 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) ]] localfunctiongetArgs(frame) localparents=mw.getCurrentFrame():getParent() fork,vinpairs(parents.args)do --check content ifvandv~=""then g.args[k]=mw.text.trim(v)--parents.args[k] end end fork,vinpairs(frame.args)do --check content ifvandv~=""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() ]] functionp.main(frame) getArgs(frame) localdataTarget=g.args[1]org.args['data'] ifdataTargetthen data=require('Module:Goalscorers/data/'..dataTarget)--or 'UEFA Euro 2016 qualifying' returnp.useModuleData(frame)-- data on goals taken from module subpage else returnp.useTemplateData(frame)-- data on goals/assists taken from template end end functionp.useModuleData(frame) --p.goalscorers = {} -- table where selected and sorted players will be place g.totalGoals=0 localok=p.selectGoalscorers()-- selected goalscorers meeting round and group criteris ifnotokthenreturnp.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 localoutputString=p.addIntroductorySentence()..p.outputGoalscorers(frame)..p.addFooterSentence() -- .. "" --TODO add intermediate heading? -- .. p._owngoals(frame) -- output list of goalscorers returnp.error_msg()oroutputString end functionp.addIntroductorySentence()-- add introductory text localtotalGoalString="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. localmatches,dateUpdated=p.getNumberMatches() localmdyFormat=yesno(g.args['mdy']) localDate=require('Module:Date')._Date localpluralGoals="s" localtext1="" ifg.totalGoals==1then pluralGoals="" ifdateUpdated=='complete'thentext1="was"elsetext1="has been"end else ifdateUpdated=='complete'thentext1="were"elsetext1="have been"end end localtext=string.format("There %s %s goal%s scored",text1,mw.getLanguage('en'):formatNum(g.totalGoals),pluralGoals) localpluralMatches="es" ifmatches==1thenpluralMatches=""end ifmatchesthen localaverage=g.totalGoals/tonumber(matches) localprecision=3-- display d.dd (three significant disgits) ifaverage<1thenprecision=2end-- display 0.dd (thwo significant disgits) average=tostring(average) localpluralAverage="s" iftonumber(string.format("%.2f",average))==1thenpluralAverage=""end text=text..string.format(" in %d match%s, for an average of %."..precision.."g goal%s per match",matches,pluralMatches,average,pluralAverage) end ifdateUpdated=='complete'ordateUpdated==""then text=text.."." else localdateFormat='dmy'-- default ifdata.paramsanddata.params['date_format']thendateFormat=data.params['date_format']end-- from data module ifmdyFormat==truethendateFormat="mdy"else ifmdyFormat==falsethendateFormat="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 returntext--totalGoalString end functionp.addFooterSentence()-- add notes at bottom localfooterSentence=g.args['footer']or"" --footerSentence = "This is a footer sentence." -- test footer ifdata.paramsthen localfooter=data.params['footer']ornil iffooterthen localframe=mw.getCurrentFrame() localprocessed=frame:preprocess(footer) ifg.notesthen footerSentence=footerSentence..processed end end end iffooterSentence~=""then footerSentence='<div style = "" >'..footerSentence..'</div>' end returnfooterSentence end functionp.getNumberMatches() localmatches=g.args['matches'] localdateUpdated=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 localround,group=p.getRoundAndGroup() localallGroupGames=0 locallatestGroupDate="1800年01月01日" ifgroupand(round=="all"orgroup=="all")then-- count all the group games fork,vinpairs(data.updated.group)do allGroupGames=allGroupGames+v[1] ifv[2]~="complete"andv[2]>latestGroupDatethenlatestGroupDate=v[2]end-- update if later date end iflatestGroupDate=="1800年01月01日"thenlatestGroupDate="complete"end-- no dates so must be complete end ifgroupand(round=="all"andgroup~="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 ifround=="all"then-- all rounds and goals matches=0 fork,vinpairs(data.updated)do ifk=="group"then matches=matches+allGroupGames iflatestGroupDate~="complete"andlatestGroupDate>dateUpdatedthen dateUpdated=latestGroupDate-- update if later date end elseifp.validateRound(k)then matches=matches+v[1] ifv[2]~="complete"andv[2]>dateUpdatedthendateUpdated=v[2]end-- update if later date end end elseifround=="group"then-- group round only ifgroup=="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 ifdateUpdated=="1700年01月01日"thendateUpdated="complete"end-- no dates so must be complete returnmatches,dateUpdated end functionp.owngoals(frame)-- need to check parameters if external call getArgs(frame) data=require('Module:Goalscorers/data/'..g.args[1])--or 'UEFA Euro 2016 qualifying' localoutputString=p._owngoals(frame) returnp.error_msg()oroutputString end functionp._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 returnp.outputGoalscorers(frame,"OG")-- output list of goalscorers end functionp.validateRound(round) localvalidateRound=false fork,vinpairs(data.rounds)do ifk==roundthenvalidateRound=trueend-- data for this round exists end returnvalidateRound 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 ]] functionp.selectGoalscorers(og) localround,group=p.getRoundAndGroup() ifnotroundthenreturnfalseend-- exit if no valid round localgoalMinimum=tonumber(g.args['minimum'])or-5-- assume 5 own goals is maximum localgoalsCol=p.getGoalsCol(round)-- first column for goals -- select players who have scored in rounds/groups requested localgoalscorerData=data.goalscorers ifog=="OG"thengoalscorerData=data.owngoalscorersend fork,vinpairs(goalscorerData)do localgoals,comment=0,""-- goals > 0 is the flag to include the player localplayerName,playerAlias=p.getPlayer(v[1])-- player name localgoalsByRound,commentByRound=0,"" ifround=="all"then-- goals in all rounds and all groups fori=goalsCol,#v,1do ifgroupandgroup~="all"andi==p.getGoalsCol("group")andgroup~=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 ifcommentByRound~=""then ifcomment==""then comment=commentByRound else comment=comment..","..commentByRound--TODO decide on comma or semi-colon end end i=i+1 end elseifround=="all2"andgroup~="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] ) ) fori=goalsCol,#v,1do ifi==p.getGoalsCol("group")andgroup~=p.getGroup(v[2],v[3])then goalsByRound=0 commentByRound="" else goalsByRound,commentByRound=p.getGoals(v[i],playerName) end goals=goals+goalsByRound ifcommentByRound~=""then ifcomment==""then comment=commentByRound else comment=comment..","..commentByRound--TODO decide on comma or semi-colon end end i=i+1 end elseifround=="group"then-- group round only ifgroup==p.getGroup(v[2],v[3])then-- single group only goals,comment=p.getGoals(v[goalsCol],playerName) elseifgroup=="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 ifgoals>=goalMinimumandgoals~=0then ifcomment~=""then ifog=="OG"then comment='<span> ('..p.sortComment(comment)..')</span>' else comment='<span>'..comment..'</span>'-- no parenthesis when using notes end end ifog=="OG"thengoals=-goalsend-- 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 returntrue-- data collected for selected goalscorers end --[[ p.getRoundAndGroup() ]] functionp.getRoundAndGroup() localround=g.args['round']or"all"-- round = all(empty)|group|playoffs localgroup=g.args['group']or"all"-- group = all(empty), A,B,C etc localvalidateRound=false localvalidateGroupRound=false fork,vinpairs(data.rounds)do ifk==roundthenvalidateRound=trueend-- data for this round exists ifk=="group"thenvalidateGroupRound=trueend-- there is a group round end ifvalidateRound==falseandround~="all"then localmessage='Invalid round "'..round..'" specified. No data found for that round. ' mw.addWarning(message) p.errorString=p.errorString..message round=nil end ifvalidateGroupRound==falsethengroup=falseend-- there is no group round -- TODO add group error checking -- Could merge with getGoalsCol() and also return goalsCol returnround,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 ]] functionp.getGoalsCol(round) localminimum=1000 ifround=="all"then-- if all need column of first round fork,vinpairs(data.rounds)do ifv<minimumthenminimum=vend --return v -- return the first one [this seemed to work reliably, but sometimes table order is not as listed] end returnminimum end ifdata.roundsanddata.rounds[round]then returndata.rounds[round]-- get column containing goals for that round else return4-- 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 ]] functionp.getGroup(country,possibleGroup)-- row contain player name, country code, group if given, goals ifdata.groupsthen fork,vinpairs(data.groups)do-- iterate through the groups --local = gotGroup = false forj,uinpairs(v)do-- for each group ifu==countrythen returnk end end end return"no group found" else returnpossibleGroup-- 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 ]] functionp.getGoals(u,player) iftype(u)=='table'andtype(u[1])=='number'then returnu[1],u[2]-- return number of goals, comment elseiftype(u)=='number'then returnu,""-- return number of goals, empty string else p.errorString=p.errorString.." Invalid goals entry for player "..player return0,"" end end functionp.parseComment(comment) localframe=mw.getCurrentFrame() -- we have something like "{{efn-ua|name=goals}}" ifstring.find(comment,"efn",1,true)then-- if we have a comment with a note g.notes=true-- set flag end returnframe:preprocess(comment) end functionp.getPlayer(u) iftype(u)=='table'then iftype(u[1])=='string'andtype(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]] returnu[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 elseiftype(u)=='string'then returnu,""-- return player name else p.errorString=p.errorString.." Invalid name entry for player "..uoru[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 ]=] functionp.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 localspecialChars={-- 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"} } fork,vinpairs(specialChars)do-- replace special characters from supplied list name=string.gsub(name,v[1],v[2]) end returnname 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 ]] functionp.getPlayerSortName(playerName,sortName,countryName) --dewikify all names before sorting, also forces lowercase playerName=p.preprocessSortName(playerName) sortName=p.preprocessSortName(sortName) ifsortName~=""then-- if we have a sort name supplied returnsortName-- then return it end -- players from certain countries will use name in order supplied localnoSort={"CAM","CHN","TPE","MYA","PRK","KOR","VIE"} fork,vinpairs(noSort)do ifv==countryNamethen returnplayerName 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 ifstring.find(playerName,"|")then-- test for redirect localnames=mw.text.split(playerName,"|") playerName=names[2]-- get name after pipe end localnames=mw.text.split(playerName," ")-- we don't want to sort on first name if#names==1then returnnames[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 localname=names[2]-- set name to second name e.g. Bloggs or van locali=3 whilei<=#namesdo-- 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 returnname-- sort on second name third name etc, first name end end -- sort the list of countries alphabetically functionp.sortComment(comment) localitems=mw.text.split(comment,",")-- split comma-delimited list fork,vinpairs(items)do items[k]=mw.text.trim(v)-- trim spaces and coe end table.sort(items,function(a,b)returna<bend)-- sort the table alphbetically locallist="against "-- construct the alphabetical list string fori=1,#itemsdo localsep=", "-- separator for comma-delimited list ifi==1thensep=""-- first word doesn't need comma elseifi==#itemsthensep=" & "-- use "and" before last word end list=list..sep..items[i] end returnlist end functionp.getCountryName(country) ifstring.len(country)==3then-- if the country given as a three-letter code localcodes=require('Module:Goalscorers/data/Country codes') fork,vinpairs(codes.alias)do ifv[1]==countrythen returnv[2] end end else returncountry-- 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 ]] functionp.sortGoalscorers() localsort_function=function(a,b) if(a.goals>b.goals)then-- primary sort on 'goals' -> a before b returntrue elseif(a.goals<b.goals)then-- primary sort on 'goals' -> b before a returnfalse else-- a.goals == b.goals -- primary sort tied, --return a.country < b.country -- resolve with secondary sort on 'country' localcountry_a=p.getCountryName(a.country)-- sort on name of country, not the code localcountry_b=p.getCountryName(b.country) if(country_a<country_b)then-- secondary sort on 'country' returntrue elseif(country_a>country_b)then-- secondary sort on 'country' returnfalse else-- a.country == b.country -- secondary sort tied, --return a.player < b.player --resolve with tertiary sort on 'player' name localplayer_a=p.getPlayerSortName(a.player,a.alias,a.country)-- get player name for sorting localplayer_b=p.getPlayerSortName(b.player,b.alias,b.country) returnplayer_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 functionp.tabulateGoalscorers(frame,og) -- ==============output the lists of goalscorers by goal====================== localgoalNumber=1000 localmaxRank=tonumber(g.args['maxrank']or10)-- limit list top ten or value in parameter maxrank localrank=1 localplayerCount=0 localrankCount=0 localplayerCells="" localfirstplayerCell="" localtableString='\n{| class="wikitable"'-- start table ..'\n|-'..'\n!Rank !! Player !! Goals'-- add table headers ifg.args['header']thentableString=tableString..'\n|+ '..g.args['header']end-- add header forj,uinpairs(g.goalscorers)do-- run through sorted list of selected goalscorers -- is the player active still? localplayerActive=false ifdata.active_countriesthen fork,vinpairs(data.active_countries)do ifv==u['country']then playerActive=true break; end end end local_,roundStatus=p.getNumberMatches() ifroundStatus=="complete"thenplayerActive=falseend-- overrides active_countries -- wikitext for tablulated list localgoalscorerString=p.addLinkedIcon(frame,u['country'])-- linked flag icon ifplayerActiveandg.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 ifu['goals']<goalNumberthen-- 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 ifplayerCount==1then 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 localrowSpan=rankCount ifplayerCount>maxRank*1.5then 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 ifrank>maxRankthenbreakend-- 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) ifgoalNumber==1andrank<=maxRankthen localrowSpan=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 iftableString~=""then tableString=tableString.."\n|}" returntableString else return(" No goals matching requested criteria.") end end functionp.outputGoalscorers(frame,og)-- output list of goalscorers ifg.args['table']thenreturnp.tabulateGoalscorers(frame,og)end-- optional table output localoutputString="" ifog=="OG"thenend -- ==============output the lists of goalscorers by goal====================== localgoalNumber=1000 --local goalMinimum = tonumber(templateArgs['minimum']) or 0 locallistOpen=false-- flag for list started by template {{Div Col}} forj,uinpairs(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) ifu['goals']<goalNumberthen-- start new list of new number of goals iflistOpenthen-- 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'] localgoalString=" goal" --if og == "OG" then ifgoalNumber<0then goalString=" own"..goalString end ifmath.abs(u['goals'])~=1thengoalString=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? localplayerActive=false ifdata.active_countriesthen fork,vinpairs(data.active_countries)do ifv==u['country']then playerActive=true break; end end end local_,roundStatus=p.getNumberMatches() ifroundStatus=="complete"thenplayerActive=falseend-- overrides active_countries -- wikitext for bullet list localgoalscorerString='\n*<span>'..p.addLinkedIcon(frame,u['country'])-- linked flag icon ifplayerActiveandg.args['bold']~='no'then goalscorerString=goalscorerString.." <b>"..u['player'].."</b>"-- bolded name else goalscorerString=goalscorerString.." "..u['player']-- name end goalscorerString=goalscorerString..u['comment']..'</span>'-- comment for o.g. outputString=outputString..goalscorerString-- .. " " .. tostring(u['goals']) end-- reached end of list of goalscorers ifoutputString~=""then outputString=outputString..p.closeList(frame) returnoutputString else return(" No goals matching requested criteria.") end end -- output icon linked to national team page functionp.addLinkedIcon(frame,country) localicon=data.templates['flag_icon_linked']-- fbicon etc set in data module locallevel=data.templates['youth_level']or""-- parameter for youth level, ie under-21 -- equivalent to {{fbicon|country}} localflagVariant="" ifdata.templates.flagvaranddata.templates.flagvar[country]then flagVariant=data.templates.flagvar[country] end iflevel~=""then returnframe:expandTemplate{title=icon,args={level,country,flagVariant}} else returnframe:expandTemplate{title=icon,args={country,flagVariant}}-- flag icon end end -- formatting of list under each number of goals functionp.openList(frame,og) returnmw.getCurrentFrame():extensionTag{ name='templatestyles',args={src='Div col/styles.css'} }..'<div class="div-col" style="column-width:25em;">'-- perhaps add "column-count:3;"" to limit max number of columns? end functionp.closeList(frame) return'</div>' end functionp.firstToUpper(str) return(str:gsub("^%l",string.upper)) end -- handles parameters bold, further, extra functionp.addAdditionHeaderText(text,dateUpdated) ifg.args['inlineref']then text=text..g.args['inlineref'] end ifg.args['bold']andg.args['bold']~='no'then text=text.." Players highlighted in '''bold''' are still active in the competition." end ifg.args['further']then iftext~=""thentext=text.." "end text=text..g.args['further'] end ifg.args['extra']then text=text.."\n\n"..g.args['extra'] end returntext end -- count number of goals for data in template functionp.countGoals(list,number,totalGoals) localsplit=mw.text.split(list,"\n",true)-- split the list for number of goals scorers with N goals localcount=#split*math.abs(number)-- calculate number of goals (including own goals) totalGoals=totalGoals+count --mw.addWarning( "Entry: " .. list .. "[" .. count .. "]") returntotalGoals end --[[ use data supplied by template ]] --function p.list(frame) functionp.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}}|}} --]] localstatNumber=mw.getLanguage('en'):formatNum(tonumber(g.args['goals']or0))--format goal number as string localmatches=g.args['matches'] localstatType="goal" ifg.args['assists']thenstatType="assist"end ifg.args['clean sheets']thenstatType="clean sheet"end localongoing=g.args['ongoing'] localtext1="There" ifg.args['lc']thentext1="there"end localtext2="were" ifongoingthentext2="have been"end localupdateString="" localaverageString="" localgoalPlural="s"-- goal(s) ifg.args['goals']andtonumber(g.args['goals'])==1then goalPlural="" text2="was" ifongoingthentext2="has been"end end localmatchPlural="es"-- match(es) ifg.args['matches']andtonumber(g.args['matches'])==1thenmatchPlural=""end -- auto version: string.format(" in %d match%s, for an average of %."..precision.."g goal%s per match", matches, pluralMatches, average, pluralAverage) ifg.args['goals']andg.args['matches']then localaverageGoals=g.args['goals']/g.args['matches'] localavGoalPlural="s" ifaverageGoals==1thenavGoalPlural=""end averageString=string.format(" in %d match%s, for an average of %.3g goal%s per match",g.args['matches'],matchPlural,averageGoals,avGoalPlural) end ifg.args['updated']andg.args['updated']~="complete"then updateString=" (as of "..g.args['updated']..")" end localsep="." ifg.args['sep']thensep=g.args['sep']end localtext="" ifg.args['goals']then text=string.format("%s %s %s %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}}''' <div class="div-col columns column-count column-count-3" style="column-count:3;"> {{#if:{{{assists|}}}|{{{30 assists}}}|{{{30 goals}}}}}</div>|}}]] localoutput="\n" localnumber=30 localtotalGoals=0 whilenumber>-4do-- for the each goals/assists localentry=g.args[number..' goals']org.args[number..' goal'] org.args[number..' assists']org.args[number..' assist'] org.args[number..' clean sheets']org.args[number..' clean sheet'] ifnumber<0then entry=g.args[math.abs(number)..' own goals']org.args[math.abs(number)..' own goal'] statType="own goal" end localplural="s" ifnumber==1ornumber==-1thenplural=""end ifentrythen-- 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 ifstatType=="goal"orstatType=="own goal"then ifg.args['goals']andtotalGoals~=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}}}}} <div class="div-col columns column-count column-count-3" style="column-count:3;"> {{{bottom}}}</div>|}}{{#if:{{{source|}}}|{{smaller|Source: {{{source}}}}}|}} localfooterText=g.args['footer-text']org.args['bottom']or"" localfooterHeading=g.args['footer-heading']org.args['bottom-text']or"" localfooter="" iffooterText~=""then localheading="" iffooterHeading~=""then heading='<p>'..footerHeading..'</p>' end footer='\n'..heading..p.openList(frame)..'\n'..footerText..p.closeList(frame) end --{{#if:{{{source|}}}|{{small|Source: {{{source}}}}}|}} localsource=g.args['source']or"" ifsource~=""thensource="<small>Source: "..source.."</small>"end returntext..output..footer..source end returnp