--[[ LoU - List of Untergangers lua module 
     to improve parsing speed of the List of Untergangers page
     by mfaizsyahmi, 2017
local libCtry = require("Dev:Country")
local libFlag = require("Module:iconflags")
local lang ="en")
local p = {}
-- constants
local ytPlFmt   = '[ ▶️️]'
local ytUserFmt = '[ ▶️️]'
local ytUcFmt   = '[ ▶️️]'
local sbUserFmt = '[ 📈]'
local sbUcFmt   = '[ 📈]'
local statusTbl = {
    ['a'] = '<span class="active">Active</span>',
    ['h'] = '<span class="hiatus">Hiatus</span>',
    ['d'] = '<span class="dormant">Dormant</span>',
    ['r'] = '<span class="retired">Retired</span>',
    ['s'] = '<span class="suicide">Suicide</span>',
    ['t'] = '<span class="terminated">Terminated</span>',
    ['x'] = '<span class="resurrected">Resurrected</span>',
    ['na']= '<span class="doubtful">Not Unterganger?</span>',
    ['a?']= '<span class="active">Active (?)</span>',
    ['h?']= '<span class="hiatus">Hiatus (?)</span>',
    ['d?']= '<span class="dormant">Dormant (?)</span>',
    ['r?']= '<span class="retired">Retired (?)</span>',
    ['s?']= '<span class="suicide">Suicide (?)</span>',
    ['t?']= '<span class="terminated">Terminated (?)</span>',
    ['x?']= '<span class="resurrected">Resurrected (?)</span>',
local sbSortKey = {
    ['A+']= 'A1',
    ['A' ]= 'A2',
    ['A-']= 'A3',
    ['B+']= 'B1',
    ['B' ]= 'B2',
    ['B-']= 'B3',
    ['C+']= 'C1',
    ['C' ]= 'C2',
    ['C-']= 'C3',
    ['D+']= 'D1',
    ['D' ]= 'D2',
    ['D-']= 'D3',
-- maps field position to variable
local colMap = {'name','reg','ctry','vids','views','subs','sbgrade','status','yt','note'}
-- column definition
   -- direct text: head, class
   -- property names: text, title, sortkey
local colDef = {
    {head="#", class="index unsortable"},
    {head="Name", class="name", text="namenote"},
    {head="Reg", class="region reg", text="reg", title="regTitle"},
    {head="Ctry", class="country ctry", text="ctryText", title="countryName"},
    {head="Vids", class="vids", text="vids"},
    --{head="Views", class="views", text="views"},
    --{head="Subs", class="subs", text="subs"},
    {head="SB", class="sbgrade sb", text="sbgrade", sortkey="sbkey"},
    {head="Status", class="status", text="status"},
    {head="Links", class="links plainlinks", text="links"}
    --{head="Links", class="yt", text="ytlink"}
-- shorthands
local function trim(str) return mw.text.trim(str) end
-- if string has parsable number, formats it, otherwise just return
----for vids, views and subs col, which sometimes has "N/A"
local function formatNumCol(str)
    local n = tonumber(str)
    if n ~= nil then
        return lang:formatNum(n)
        return str
local function empty(a)
	return a==nil or a==""
function p.empty(a) return empty(a) end
Table row builder 
el: the table element
map: the column definition table
tbl: table containing properties to map
header: if not nil build the headers
local function buildTableRow(el, map, tbl, header)
    -- create the row builder
    local row= mw.html.create('tr')
    if empty(header) and not empty(tbl.noajax) then
    local cellTag = 'td'
    if not empty(header) then cellTag = 'th' end
    -- go through every item in the column map
    -- attr: the individual map item
    for i, attr in pairs(map) do
        -- the cell text
        -- pulls from tbl variable as defined in attr.text
        local text = tbl[attr.text] or ""
        -- if building header take the header instead
        if not empty(header)  then text = attr.head end
        -- create cell builder; apply text, class, title
        local cell = mw.html.create(cellTag)
            :attr("class", attr.class or "")
            :attr("title", tbl[attr.title] or "")
        if not empty(attr.sortkey) then
            cell:attr("data-sort-value", tbl[attr.sortkey] or "")
        -- append cell to row
    -- append row to el
local function readRecordPage(pgName, pgNS, RS, FS, colMap, shift, pop)
    local dataPage =,pgNS)
    local dataStr = dataPage:getContent()
    -- rmv newlines
    dataStr = mw.ustring.gsub(dataStr,'\n', '')
    local recordTbl={}
    for recordStr in mw.ustring.gmatch(dataStr, "([^"..RS.."]+)") do
        -- dropped split method because we want to map the vars immediately
        -- split record fields manually
        local fieldTbl = {}
        local j=1
        --for fieldStr in mw.ustring.gmatch(recordStr, "([^"..FS.."]*)") do
        -- have to use gsplit to get empty fields (those actually exists!)
        for fieldStr in mw.text.gsplit(recordStr, FS) do
            if empty(fieldStr) then mw.log('found empty field') end
            -- try and match key=value pair
            local fn = mw.ustring.gmatch(fieldStr, '[^=]+')
            local s1, s2 = fn(), fn()
            if s2 ~= nil then -- k/v match found
                fieldTbl[trim(s1)] = trim(s2)
            elseif colMap~= nil then --unnamed but mappable value
                fieldTbl[colMap[j]] = trim(fieldStr)
            else -- unnamed value
                fieldTbl[j] = trim(fieldStr)
            j = j + 1
        table.insert(recordTbl, fieldTbl)
    if shift == true then table.remove(recordTbl,1) end
    if pop == true then table.remove(recordTbl) end
    return recordTbl
function p.main(frame)
    -- retrieve arguments
    local fArgs = frame.args--.getParent()
    local LoUNS = fArgs.ns or 0
    local LoUPage = or "List of Untergangers/data"
    local RS = or "§" -- record separator
    local FS = fArgs.fs or "‖" -- field separator
    -- read the record file and extract record table
    local recordTbl = readRecordPage(LoUPage,LoUNS,RS,FS,colMap,true,true)
    -- create the table builder
    local tableEl = mw.html.create('table')
    tableEl:attr("class", "untergangers wikitable fullwidth sortable hilight floatheader")
    -- build the header
    buildTableRow(tableEl, colDef, {}, true)
    -- iterate each record to build the table entry rows
    --for _, record in pairs(recordTbl) do
    for _, t in pairs(recordTbl) do
        -- extract record fields into table
        --[[now that we mapped arrays to vars in readRecordPage the whole
            block below is skipped. hopefully this would speed up parsing.]]
        --[[local t = {
            name = or record[1] or "",
            reg  = record.reg or record[2] or "",
            ctry = trim(record.ctry or record[3] or ""),
            vids = record.vids or record[4] or "",
            views= record.views or record[5] or "",
            subs = record.subs or record[6] or "",
            sbgrade = trim(record.rank or record[7] or ""),
            status = record.status or record[8] or "",
            yt = or record[9] or "",
            pl = or "",
            noajax = record.noAjax or "",
            note = record.note or record[10] or "",
            -- initialize other vars
            namenote = "",
            regTitle = "",
            ctryText = "",
            sbkey = "",
            ytlink = "",
            sblink = "",
            links  = ""
        --deriving values from the variables
        ----name and note
        if not empty(t.note) then
            t.namenote = ..' <small>('.. t.note ..')</small>'
            t.namenote =
        ----country and region
        t.ctry = t.ctry or '' --fix nil
        t.countryCode = mw.ustring.lower(t.ctry)
        ----HPW accepts uk as synonym for gb
        if t.countryCode == 'uk' then t.countryCode = 'gb' end
        if not empty(t.countryCode) then
            t.countryName = libCtry.main{t.countryCode,'name'}
            t.region = libCtry.main{t.countryCode,'region'}
            t.subregion = libCtry.main{t.countryCode,'sub-region'}
            t.flag = libFlag.flag{t.countryCode, useemoji='om'}
            if empty(t.reg) then
                t.reg = ".."
            ----the title for region cell
            t.regTitle = t.region .." – ".. t.subregion
            ----text for ctry cell
            t.ctryText = t.flag .. t.ctry
            --t.countryName = ""
            --t.region = ""
            --t.subregion = ""
            --t.flag = ""
        -- numbers
        t.vids = formatNumCol(t.vids)
        t.views = formatNumCol(t.views)
        t.subs = formatNumCol(t.subs)
        -- status and grade
        t.status = statusTbl[t.status] or t.status
        t.sbkey = sbSortKey[t.sbgrade] or 'Z'
        -- yt link = or '' -- fix nil
        -- tilde means take the name argument
        if == '~' then
            _, _, = mw.ustring.find(,'%[?%[?([^%]]*)%]?%]?')
        if not empty( then -- playlist defined
            t.ytlink = mw.ustring.format(ytPlFmt,
            t.sblink = ''
        elseif mw.ustring.len( 
            and mw.ustring.sub(,1,2)=='UC' then
            -- yt matches channel ID (string of 24 char length begin w/ UC)
            t.ytlink = mw.ustring.format(ytUcFmt,
            t.sblink = mw.ustring.format(sbUcFmt,
        elseif not empty( then -- old username
            t.ytlink = mw.ustring.format(ytUserFmt,
            t.sblink = mw.ustring.format(sbUserFmt,
        else -- absent
            t.ytlink = ''
            t.sblink = ''
        t.links = t.ytlink..' '..t.sblink
        -- finally build the row given the table of variables
        buildTableRow(tableEl, colDef, t)
    -- return the text returned by the html builder
    return tableEl:done()
function p.item(frame)
    -- retrieve arguments
    local fArgs = frame.args--.getParent()
    local LoUNS = fArgs.ns or "User"
    local LoUPage = or "Mfaizsyahmi/testdata"
    local RS = or "§" -- record separator
    local FS = fArgs.fs or "‖" -- field separator
    local dataPage =,LoUNS)
    local dataStr = dataPage:getContent()
    dataStr = mw.ustring.gsub(dataStr,'\n', '')
return p

Ad blocker interference detected!

Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.