Modul ini untuk menampilkan daftar pencetak gol sepak bola; digunakan pada banyak artikel kompetisi sepak bola.
| Modul ini dinilai sebagai modul beta, dan siap digunakan secara luas. Modul ini masih baru dan harus digunakan dengan hati-hati untuk memastikan bahwa hasilnya sesuai dengan yang diharapkan. |
Sub-halaman Data
- Goalscorers/data/Country codes
- Goalscorers/data/Kejuaraan Perbara 2026
- Goalscorers/data/Kualifikasi Piala Asia AFC 2023
- Goalscorers/data/Kualifikasi Piala Asia AFC 2027
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2022 (AFC)
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2022 (AFC)/doc
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2026 (AFC)
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2026 (CAF)
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2026 (CONCACAF)
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2026 (OFC)
- Goalscorers/data/Kualifikasi Piala Dunia FIFA 2026 (UEFA)
- Goalscorers/data/Kualifikasi UEFA Euro 2020
- Goalscorers/data/Kualifikasi UEFA Euro 2024
- Goalscorers/data/Liga Negara UEFA 2020–2021
- Goalscorers/data/Liga Negara UEFA 2022–2023
- Goalscorers/data/Liga Negara UEFA 2024–2025
- Goalscorers/data/Liga Negara UEFA 2026–2027
- Goalscorers/data/Piala Dunia FIFA 2026
- Goalscorers/data/Piala Perbara FIFA 2026
PenggunaanPenggunaan
{{#invoke:Goalscorers|main}}
Modul ini digunakan templat {{goalscorers}}.
Dokumentasi di atas ditransklusikan dari Modul:Goalscorers/doc. (sunting | riwayat)
Penyunting dapat melakukan uji coba pada halaman bak pasir (sunting | beda) dan kasus uji (buat) modul ini.
Subhalaman modul ini.
Penyunting dapat melakukan uji coba pada halaman bak pasir (sunting | beda) dan kasus uji (buat) modul ini.
Subhalaman modul ini.
require('strict'); localyesno=require('Modul: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('Modul: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. "Modul: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 ############################### this section is currently unused will be used to take check parameters set in 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() - menambah kalimat/paragraf pembuka jumlah gol dan rata-rata gol per pertandingan p.addFooterSentence() - menambah catatan kaki 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('Modul: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 -- 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 --[[ ##################### standalone value outputs ########################## p.goals(frame) - output ONLY the total number of goals scored p.matches(frame) - output ONLY the number of matches played p.date(frame) - output ONLY the date of the most recent matches played accepts optional |format=yes to comma-format the number (e.g. 1,234). ]] functionp.goals(frame) getArgs(frame) localresult localdataTarget=g.args[1]org.args['data'] ifdataTargetthen data=require('Modul:Goalscorers/data/'..dataTarget) g.goalscorers={}-- reset state (safe for multiple invokes per page) g.totalGoals=0 localok=p.selectGoalscorers()-- count goals for selected round/group ifnotokthenreturnp.error_msg()end p.selectGoalscorers("OG")-- include own goals in the total ifp.errorString~=""thenreturnp.error_msg()end result=g.totalGoals else result=tonumber(g.args['goals'])or0-- fall back to template-supplied data end ifyesno(g.args['format'])then returnmw.getLanguage('en'):formatNum(result) end returntostring(result) end functionp.matches(frame) getArgs(frame) localresult localdataTarget=g.args[1]org.args['data'] ifdataTargetthen data=require('Modul:Goalscorers/data/'..dataTarget) localround=g.args['round']or"all" ifround~="all"andnotp.validateRound(round)then-- guard against bad round p.errorString=p.errorString..'Invalid round "'..round..'" specified. ' returnp.error_msg() end result=p.getNumberMatches()-- respects round/group args else result=tonumber(g.args['matches'])or0 end ifyesno(g.args['format'])then returnmw.getLanguage('en'):formatNum(result) end returntostring(result) end functionp.date(frame) getArgs(frame) localdataTarget=g.args[1]org.args['data'] ifnotdataTargetthenreturng.args['updated']or""end-- template-data fallback data=require('Modul:Goalscorers/data/'..dataTarget) localround=g.args['round']or"all" ifround~="all"andnotp.validateRound(round)then p.errorString=p.errorString..'Invalid round "'..round..'" specified. ' returnp.error_msg() end local_,dateUpdated=p.getNumberMatches() ifdateUpdated=="complete"ordateUpdated==""thenreturn""end-- nothing to show localdateFormat=(data.paramsanddata.params['date_format'])or'dmy' localmdy=yesno(g.args['mdy']) ifmdy==truethendateFormat="mdy"elseifmdy==falsethendateFormat="dmy"end localr,grp=p.getRoundAndGroup() localfinished=p.matchesFinished(r,grp,dateUpdated) iffinished~=""thenfinished=" ("..finished..")"end returnp.error_msg()or(require('Modul:Date')._Date(dateUpdated):text(dateFormat)..finished) end --[[ ##################### matches-finished helper ############################ p.matchesFinished(round, group, latestDate) Sums the optional "F/T" field (3rd element of a data.updated entry) for every entry dated on latestDate. Older dates are ignored. Returns "" when no entry supplies F/T, or a contributing entry on that date lacks it. ]] functionp.matchesFinished(round,group,latestDate) ifnotlatestDateorlatestDate=="complete"orlatestDate==""orlatestDate=="1700-01-01"then return"" end localentries={}-- entries applying to round/group ifround=="all"then fork,vinpairs(data.updated)do ifk~="date"andk~="group"andp.validateRound(k)thenentries[#entries+1]=vend end elseifround~="group"then entries[#entries+1]=data.updated[round] end if(round=="all"orround=="group")anddata.updated.groupthen ifgroupandgroup~="all"then entries[#entries+1]=data.updated.group[group] else for_,vinpairs(data.updated.group)doentries[#entries+1]=vend end end localfinished,total,found=0,0,false-- sum F/T on the most-recent date for_,einipairs(entries)do ife[2]==latestDatethen localf,t=string.match(tostring(e[3]or""),"^%s*(%d+)%s*/%s*(%d+)%s*$") ifnotfthenreturn""end-- contributing entry without F/T -> skip finished,total,found=finished+f,total+t,true end end ifnotfoundthenreturn""end iffinished>=totalorfinished<1ortotal<1thenreturn""end-- all done / invalid -> date only returnfinished.."dari"..total.."pertandinganselesai" end functionp.addIntroductorySentence()-- menambahkan teks/paragraf awal localtotalGoalString="Sebanyak"..g.totalGoals.."dicetak." localmatches,dateUpdated=p.getNumberMatches() localmdyFormat=yesno(g.args['mdy']) localDate=require('Modul:Date')._Date localtext1="" ifg.totalGoals>=1then ifdateUpdated~='complete'ordateUpdated~='completed'ordateUpdated~='selesai'thentext1="telah dicetak"end else ifdateUpdated=='complete'ordateUpdated=='completed'ordateUpdated=='selesai'thentext1="dicetak"end end localtext=string.format("Sebanyak %s gol %s",mw.getLanguage('id'):formatNum(g.totalGoals),text1) ifmatchesthen localaverage=g.totalGoals/tonumber(matches)-- menghitung rata-rata gol localprecision=3-- presisi dua angka dibelakang koma ifaverage<1thenprecision=2end-- presisi satu angka dibelakang koma average=string.format("%."..precision.."g",average) text=text..string.format(" pada %d pertandingan, dengan rata-rata %s gol per pertandingan",matches,mw.getLanguage('id'):formatNum(tonumber(average))) end ifdateUpdated=='complete'ordateUpdated=='completed'ordateUpdated=='selesai'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 localround,group=p.getRoundAndGroup() localfinished=p.matchesFinished(round,group,dateUpdated) iffinished~=""thenfinished=", "..finishedend text=text.." (per "..Date(dateUpdated):text(dateFormat)..finished..")." end text=p.addAdditionHeaderText(text,dateUpdated)-- handles template parameters bold, further, extra returntext--totalGoalString end functionp.addFooterSentence()-- menambahkan teks akhir/catatan kaki 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('Modul: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 funtion ]] --[=[ 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"},{"đ","dj"}, {"ă","a"},{"â","a"},{"ż","z"}, {"ț","t"},{"ş","s"},{"ś","s"}, {"ǎ","a"},{"ě","e"},{"ů","u"}, {"ĕ","e"},{"ñ","n"},{"ď","d"}, {"ï","i"},{"ź","z"},{"ô","o"}, {"ė","e"},{"ľ","l"},{"ģ","g"}, {"ļ","l"},{"ę","e"},{"ň","n"}, {"ò","o"},{"ō","o"},{"î","i"}, {"õ","o"},{"œ","oe"} } 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="melawan "-- construct the alphabetical list string fori=1,#itemsdo localsep=", "-- separator for comma-delimited list ifi==1thensep=""-- first word doesn't need comma elseifi==#itemsthensep=" dan "-- 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('Modul: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!<abbr title="Peringkat">Per.</abbr> !! Pemain !! Gol'-- 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 ifrowSpan>1and(playerCount>maxRankor(rank+rowSpan-1)>maxRank)then firstplayerCell='\n| style="font-style:italic;text-align:center;"|'..rankCount.." pemain" 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 -- if all scorers on one goal, tableString isn't updated in loop above (may need to generalise for other goal number) ifgoalNumber==1andrank<=maxRankthen localtotalInGroup=rankCount+1 localrowSpan=totalInGroup -- jika pada grup terkecil playerCount > maxRank iftotalInGroup>1and(playerCount>maxRankor(rank+totalInGroup-1)>maxRank)then firstplayerCell='\n| style="font-style:italic;text-align:center;"|'..totalInGroup.." pemain" playerCells="" rowSpan=1 end 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(" Tidak ada gol yang sesuai dengan kriteria yang diminta.") 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=" gol" --if og == "OG" then ifgoalNumber<0then goalString=string.format("%s bunuh diri",goalString) end ifmath.abs(u['goals'])~=1thengoalString=goalStringend 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(" Tidak ada gol yang sesuai dengan kriteria yang diminta.") end end -- output icon linked to national team page functionp.addLinkedIcon(frame,country) g.iconCache=g.iconCacheor{} localcache=g.iconCache[data]-- per data module (safe across invokes) ifnotcachethencache={};g.iconCache[data]=cacheend ifcache[country]~=nilthenreturncache[country]end-- already built for this team localicon=data.templates['flag_icon_linked']-- fbicon etc set in data module localflagvar=data.templates.flagvaranddata.templates.flagvar[country] locallevel=data.templates['youth_level']-- youth level, e.g. under-21 localresult localavar=({fbicon='fb',fbwicon='fbw',fbuicon='fbu',fbwuicon='fbwu'})[icon] ifavarthen -- {{#invoke:flagg|main|pxxl|avar=fb|variant=VAR|CODE}} result=require('Module:Flagg').luaMain(frame, {'pxxl',avar=avar,age=level,variant=flagvar,country}) else localargs={country,flagvaror""} iflevelthen table.insert(args,1,level) end result=frame:expandTemplate{title=icon,args=args} end cache[country]=result returnresult 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.." Pemain dengan '''cetak tebal''' masih bermain pada turnamen ini." 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|}}}||Sebanyak {{{goals}}} {{#ifexpr:{{{goals}}}=1|gol|gol}} telah dicetak {{#if:{{{players|}}}| oleh {{{players}}} {{#ifexpr:{{{players}}}=1|pemain|pemain yang berbeda}} {{#if:{{{own_goals|}}}| (dengan {{{own_goals}}} gol di antaranya termasuk ke dalam {{#ifexpr:{{{own_goals}}}=1|gol bunuh diri|gol bunuh diri}})|}}|}} pada {{{matches}}} {{#ifexpr:{{{matches}}}=1|pertandingan|pertandingan}}, dengan rata-rata {{formatnum: {{#expr:{{{goals}}}/{{{matches}}} round 2}}}} {{formatnum:{{#ifexpr:({{{goals}}}/{{{matches}}} round 2)=1|gol|gol}}}} per pertandingan.}} {{#if:{{{bold|}}}|{{#if:{{{assists|}}}|| }}Pemain dengan '''cetak tebal''' masih bermain pada turnamen ini.|}} {{#if:{{{further|}}}|{{#if:{{{assists|}}}|| }}{{{further}}}|}} {{#if:{{{extra|}}}|{{{extra}}}{{clear}}|}} --]] localstatNumber=mw.getLanguage('id'):formatNum(tonumber(g.args['goals']or0))--format number as string localmatches=g.args['matches'] localstatType="gol" ifg.args['assists']org.args['umpan gol']thenstatType="umpan gol"end ifg.args['clean sheets']org.args['nirbobol']thenstatType="nirbobol"end localongoing=g.args['ongoing'] localtext1="Sebanyak" ifg.args['lc']thentext1="sebanyak"end localtext2="" ifongoingthentext2="telah"end localupdateString="" localaverageString="" -- auto version: string.format(" pada %d pertandingan, dengan rata-rata %.3g gol per pertandingan") ifg.args['goals']andg.args['matches']then localaverageGoals=g.args['goals']/g.args['matches'] averageString=string.format("%.3g",averageGoals) end ifg.args['updated']andg.args['updated']~="complete"andg.args['updated']~="completed"andg.args['updated']~="selesai"then updateString=" (per "..g.args['updated']..")" end localsep="." ifg.args['sep']thensep=g.args['sep']end localtext="" ifg.args['goals']then--Sebanyak %statNumber %statType telah dicetak pada %matches pertandingan, dengan rata-rata %averageString per pertandingan (%updateString) text=string.format("%s %s %s %s dicetak pada %d pertandingan, dengan rata-rata %s gol per pertandingan"..updateString..sep, text1,statNumber,statType,text2,g.args['matches'],mw.getLanguage('id'):formatNum(tonumber(averageString))) 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="gol bunuh diri" end ifentrythen-- do we have goals/assists for this number output=output.."\n'''"..tostring(math.abs(number)).." "..statType.."'''\n" ..p.openList(frame).."\n"..entry..p.closeList(frame) totalGoals=p.countGoals(entry,number,totalGoals) end number=number-1 end ifstatType=="gol"orstatType=="gol bunuh diri"then ifg.args['goals']andtotalGoals~=tonumber(g.args['goals'])then mw.addWarning("PERINGATAN. Jumlah gol pada terdaftar ("..totalGoals..") dan parameter gol ("..g.args['goals']..") tidak cocok.") 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>Sumber: "..source.."</small>"end returntext..output..footer..source end --[[ ######################## top scorer output ############################### p.topscorer(frame) - output the top goalscorer(s) for the whole competition |maxlist= how many tied players to list before collapsing to generic "N players" text (default 5) |basepage= page used in the collapsed link (default: current page) |section= section anchor for that link (default: Goalscorers) ]] functionp.topscorer(frame) getArgs(frame) localdataTarget=g.args[1]org.args['data'] ifnotdataTargetthenreturn""end-- this feature needs module data data=require('Modul:Goalscorers/data/'..dataTarget) g.goalscorers={}-- reset state (safe across invokes) g.totalGoals=0 localok=p.selectGoalscorers()-- regular goals only; own goals ignored ifnotokthenreturnp.error_msg()end p.sortGoalscorers()-- sorts by goals desc, then country, name if#g.goalscorers==0thenreturn""end-- no scorers -> output nothing -- collect the tied leaders (sorted, so they sit at the front of the list) localtopGoals=g.goalscorers[1].goals localleaders={} for_,vinipairs(g.goalscorers)do ifv.goals==topGoalsthen leaders[#leaders+1]=v else break end end localnumTied=#leaders localmaxList=tonumber(g.args['maxlist'])or5 -- local goalWord = (topGoals == 1) and "goal" or "goals" localoutput ifnumTied==1then-- single top scorer localv=leaders[1] output=p.addLinkedIcon(frame,v.country).." "..v.player ..' <span class="nowrap">('..topGoals..' gol)</span>' elseifnumTied<=maxListthen-- list each tied player localmList=require('Modul:List') locallistArgs={class='nowrap'} for_,vinipairs(leaders)do listArgs[#listArgs+1]=p.addLinkedIcon(frame,v.country).." "..v.player end listArgs[#listArgs+1]='(masing-masing '..topGoals..' gol)' output=mList.makeList('unbulleted',listArgs) else-- too many tied -> generic text localmList=require('Modul:List') localcn=require('Modul:ConvertNumeric') localwrittenNum=cn.spell_number2{num=numTied,capitalize=true}-- e.g. 7 -> "Seven" localbasePage=g.args['basepage']ormw.title.getCurrentTitle().text localsection=g.args['section']or'Pencetak gol' output=mList.makeList('unbulleted',{ class='nowrap', "''[["..basePage.."#"..section.."|"..writtenNum.." pemain]]''", '(masing-masing '..topGoals..' gol)' }) end returnp.error_msg()oroutput end returnp