Toggle menu
Toggle preferences menu
Toggle personal menu
Not logged in
Your IP address will be publicly visible if you make any edits.

Module:ESTable: Difference between revisions

From Teriock
Content deleted Content added
// via Wikitext Extension for VSCode
// via Wikitext Extension for VSCode
Line 436: Line 436:
-- Call the getTable function to generate the table
-- Call the getTable function to generate the table
return p.getTable(frame, elements, parts, ops)
return p.getTable(frame, elements, parts, ops)
end

function p.all(frame)
return p.getTable(frame, 'all', 'all', 'all')
end
end



Revision as of 18:59, 31 March 2025

Documentation for this module may be created at Module:ESTable/doc

local p = {}

-- Column mappings
local columns = {
    op = 1,
    celestial_nouns = 2,
    celestial_verbs = 3,
    adjectives = 4,
    adverbs = 5,
    pronouns = 6,
    propositions = 7,
    conjunctives = 8,
    articles = 9,
    flame_verbs = 10,
    flame_nouns = 11,
    storm_verbs = 12,
    storm_nouns = 13,
    life_verbs = 14,
    life_nouns = 15,
    necro_verbs = 16,
    necro_nouns = 17,
    nature_verbs = 18,
    nature_nouns = 19
}

local backgrounds = {
    op = '#f9f06b1A',
    celestial_nouns = '#dc8add1A',
    celestial_verbs = '#dc8add1A',
    adjectives = '#dc8add1A',
    adverbs = '#dc8add1A',
    pronouns = '#dc8add1A',
    propositions = '#dc8add1A',
    conjunctives = '#dc8add1A',
    articles = '#dc8add1A',
    flame_verbs = '#f661511A',
    flame_nouns = '#f661511A',
    storm_verbs = '#99c1f11A',
    storm_nouns = '#99c1f11A',
    life_verbs = '#ffffff1A',
    life_nouns = '#ffffff1A',
    necro_verbs = '#77767b1A',
    necro_nouns = '#77767b1A',
    nature_verbs = '#8ff0a41A',
    nature_nouns = '#8ff0a41A'
}

local backgrounds_even = {
    op = '#e5a50a1A',
    celestial_nouns = '#6135831A',
    celestial_verbs = '#6135831A',
    adjectives = '#6135831A',
    adverbs = '#6135831A',
    pronouns = '#6135831A',
    propositions = '#6135831A',
    conjunctives = '#6135831A',
    articles = '#6135831A',
    flame_verbs = '#a51d2d1A',
    flame_nouns = '#a51d2d1A',
    storm_verbs = '#1a5fb41A',
    storm_nouns = '#1a5fb41A',
    life_verbs = '#9a99961A',
    life_nouns = '#9a99961A',
    necro_verbs = '#0000001A',
    necro_nouns = '#0000001A',
    nature_verbs = '#26a2691A',
    nature_nouns = '#26a2691A'
}

local links = {
    flame_verbs = '{{L|Class|Flame Mage|Flame Verbs}}',
    flame_nouns = '{{L|Class|Flame Mage|Flame Nouns}}',
    storm_verbs = '{{L|Class|Storm Mage|Storm Verbs}}',
    storm_nouns = '{{L|Class|Storm Mage|Storm Nouns}}',
    life_verbs = '{{L|Class|Life Mage|Life Verbs}}',
    life_nouns = '{{L|Class|Life Mage|Life Nouns}}',
    necro_verbs = '{{L|Class|Necromancer|Necro Verbs}}',
    necro_nouns = '{{L|Class|Necromancer|Necro Nouns}}',
    nature_verbs = '{{L|Class|Nature Mage|Nature Verbs}}',
    nature_nouns = '{{L|Class|Nature Mage|Nature Nouns}}'
}

-- Helper function to parse the source table
local function parseTable(frame, output)
    local source = mw.text.split(frame:preprocess('{{:MediaWiki:ESTable}}'), '\n')
    local data = {}
    
    for i, line in ipairs(source) do
        if line:match('^|%-') then
            -- Skip separator lines
        elseif line:match('^|') then
            local row = {}
            for cell in line:gmatch('|%sall([^||]+)%sall') do
                table.insert(row, cell:match('^%sall(.-)%sall$'))
                -- output = output .. cell .. '\n'
            end
            if #row > 0 then
                table.insert(data, row)
            end
        end
    end
    
    return data, output
end

-- Helper function to trim whitespace and new lines
local function trim(s)
    return s:match('^%sall(.-)%sall$')
end

local function supertrim(s)
    return s:match('^%sall(.-)%sall$'):gsub('%d', '')
end

-- Main function to generate filtered table
function p.filter(frame)
    local output = ''
    local args = frame.args
    local data, output = parseTable(frame, output)
    -- if true then
    --     return data
    -- end
    local selectedCols = {}

    if args then
        -- Trim whitespace from args
        for k, v in pairs(args) do
            args[k] = trim(v)
        end

        -- Remove empty arguments
        for k, v in pairs(args) do
            if v == '' then
                args[k] = nil
            end
        end
        
        -- Determine which columns to show
        for k, v in pairs(args) do
            if ((v ~= '') and columns[k]) then
                table.insert(selectedCols, {name = k, index = columns[k]})
            end
        end
    end

    local bg = (args.bg ~= '')

    -- Sort columns by their original index
    table.sort(selectedCols, function(a, b) return a.index < b.index end)

    -- for _, col in ipairs(selectedCols) do
    --     output = output .. ' !! ' .. tostring(col.index)
    -- end

    -- output = output .. '\n\n'
    
    -- Generate output table
    output = output .. '{| class="mw-collapsible mw-collapsed wikitable sortable"\n|+ style=white-space:nowrap | Elder Sorcery Words\n'
    
    -- Header row
    -- output = output .. '! OP'
    -- for _, col in ipairs(selectedCols) do
    --     local header = col.name:gsub("_", " "):gsub("^%l", string.upper)
    --     output = output .. ' !! ' .. header
    -- end
    -- output = output .. '\n'
    
    -- Data rows
    local header = true
    for _, row in ipairs(data) do
        if (#row > 0) and (#selectedCols > 0) then
            output = output .. '\n\n|-\n\n'
            local dontskip = false
            row_content = ''
            for _, col in ipairs(selectedCols) do
                if header then
                    d = '!'
                else
                    d = '|'
                end
                content = d
                op = tonumber(row[1]) or 0
                if bg then
                    if op % 2 == 0 then
                        content = content .. ' style="background-color: ' .. backgrounds_even[col.name] .. '" |'
                    else
                        content = content .. ' style="background-color: ' .. backgrounds[col.name] .. '" |'
                    end
                    -- content = content .. ' style="background-color: ' .. backgrounds[col.name] .. '" |'
                end
                word = tostring(row[col.index])
                if links[word] then
                    word = frame:preprocess(links[word])
                end
                if supertrim(word) ~= '' then
                    dontskip = true
                end
                content = content .. ' ' .. word .. ' ' .. d
                row_content = row_content .. content
            end
            if dontskip then
                output = output .. row_content
            end
            output = output:sub(1, -3)
            -- output = output .. '\n'
        end
        if header then
            header = false
        end
    end
    
    output = output .. '\n|}'
    return output
end

-- NEW CONTENT
-- -----------

local esw = require('Module:ESWords')

local words = esw.words()

local function contains(tbl, val)
    for _, v in ipairs(tbl) do
        if v == val then return true end
    end
    return false
end

local function fixInputs(elements, parts, ops)
    if elements == "all" then
        elements = {}
        for elementName, _ in pairs(words) do
            table.insert(elements, elementName)
        end
    end

    if parts == "all" then
        parts = {}
        local firstElement = next(words)
        if firstElement then
            for partName, _ in pairs(words[firstElement]) do
                table.insert(parts, partName)
            end
        end
    end

    if ops == "all" then
        ops = {}
        local firstElement = next(words)
        if firstElement then
            local firstPart = next(words[firstElement])
            if firstPart then
                for opLevel, _ in pairs(words[firstElement][firstPart]) do
                    table.insert(ops, opLevel)
                end
            end
        end
    end

    -- Normalize inputs to tables if they are not already
    if type(elements) ~= "table" then
        elements = { elements }
    end
    if type(parts) ~= "table" then
        parts = { parts }
    end
    if type(ops) ~= "table" then
        ops = { ops }
    end
    return elements, parts, ops
end

local function filterWords(elements, parts, ops)
    local outWords = {}
    for elementName, elementData in pairs(words) do
        if contains(elements, elementName) then
            outWords[elementName] = {}
            for _, part in ipairs(parts) do
                if elementData[part] then
                    outWords[elementName][part] = {}
                    for _, op in ipairs(ops) do
                        if elementData[part][op] then
                            outWords[elementName][part][op] = elementData[part][op]
                        end
                    end
                end
            end
        end
    end
    return outWords
end

local bgs = {
    even = {
        op = '#e5a50a1A',
        celestial = '#6135831A',
        flame = '#a51d2d1A',
        storm = '#1a5fb41A',
        life = '#9a99961A',
        necro = '#0000001A',
        nature = '#26a2691A',
    },
    odd = {
        op = '#f9f06b1A',
        celestial = '#dc8add1A',
        flame = '#f661511A',
        storm = '#99c1f11A',
        life = '#ffffff1A',
        necro = '#77767b1A',
        nature = '#8ff0a41A',
    }
}

local function bgHex(rowNum, col)
    -- Determine the background color based on the row number and column type
    local bgColor
    if rowNum % 2 == 0 then
        -- Even row
        bgColor = bgs.even[col]
    else
        -- Odd row
        bgColor = bgs.odd[col]
    end
    return bgColor or '#ffffff1A' -- Fallback to white if no color is defined
end

local function bgStr(rowNum, col)
    -- Generate the background style string for a given row and column
    local bgColor = bgHex(rowNum, col)
    return ' style="background-color: ' .. bgColor .. '" | '
end

function p.getWords(frame, elements, parts, ops)
    elements, parts, ops = fixInputs(elements, parts, ops)
    return filterWords(elements, parts, ops)
end

function p.getTable(frame, elements, parts, ops)
    elements, parts, ops = fixInputs(elements, parts, ops)
    local outWords = filterWords(elements, parts, ops)
    
    out = '{| class="wikitable sortable"\n|+ style=white-space:nowrap | Elder Sorcery Words\n'
    -- Header row
    local rowNum = 0
    out = out .. '!' .. bgStr(rowNum, 'op') .. 'OP'
    local actualColumns = {}
    table.sort(elements, function(a, b) return a < b end)
    for _, elementName in pairs(elements) do
        table.sort(parts, function(a, b) return a < b end)
        for _, part in pairs(parts) do
            if outWords[elementName] and outWords[elementName][part] and (#outWords[elementName][part] > 0) then
                local elementTitle = elementName:gsub("_", " "):gsub("^%l", string.upper)
                local titleLink = elementName .. " Mage"
                if elementTitle == "Necro" then
                    elementTitle = "Necromancy"
                    titleLink = "Necromancer"
                end
                local partTitle = part:gsub("_", " "):gsub("^%l", string.upper)
                local titleText = elementTitle .. ' ' .. partTitle
                local title = '{{L|Class|' .. titleLink .. '|' .. titleText .. '}}'
                if elementName == "celestial" then
                    title = titleText
                end
                out = out .. ' !!' .. bgStr(rowNum, elementName) .. frame:preprocess(title)
                table.insert(actualColumns, {
                    element = elementName,
                    part = part
                })
            end
        end
    end
    rowNum = rowNum + 1
    local opRowNum = 1

    local wordCollections = {}
    -- Collect all words for each OP level
    for opLevel = 1, 10 do
        wordCollections[opLevel] = {}
        local numRows = 0
        for _, column in ipairs(actualColumns) do
            local columnElement = column.element
            local columnPart = column.part
            local columnNumRows = 0
            local columnWords = {}
            if outWords[columnElement] and outWords[columnElement][columnPart] and outWords[columnElement][columnPart][opLevel] then
                columnWords = outWords[columnElement][columnPart][opLevel]
                columnNumRows = #columnWords
            end
            numRows = math.max(numRows, columnNumRows)
            table.sort(columnWords, function(a, b) return a < b end)
            for word in pairs(columnWords) do
                -- Ensure we have a sorted list of words for this column and op level
                columnWords[word] = columnWords[word] -- This ensures the order is maintained
            end
            -- Store the words for this column and op level
            wordCollections[opLevel][columnElement .. "_" .. columnPart] = {
                words = columnWords,
                count = columnNumRows
            }
        end
        -- Now we have the max number of rows for this OP level, we can proceed to build the table
        -- Iterate over each column to build the rows for this OP level
        for rowIndex = 1, numRows do
            out = out .. '\n|-\n' -- Start a new row
            if rowIndex == 1 then
                out = out .. '|rowspan="' .. tostring(numRows) .. '" ' ..bgStr(opRowNum, 'op') .. opLevel
                opRowNum = opRowNum + 1
            else
                out = out .. ' '
            end
            for _, column in ipairs(actualColumns) do
                local columnElement = column.element
                local columnPart = column.part
                local cellContent = ''
                if wordCollections[opLevel][columnElement .. "_" .. columnPart] and wordCollections[opLevel][columnElement .. "_" .. columnPart].words[rowIndex] then
                    cellContent = wordCollections[opLevel][columnElement .. "_" .. columnPart].words[rowIndex]
                end
                -- Add the cell content to the output
                out = out .. '\n|' .. bgStr(rowNum, columnElement) .. cellContent
            end
            rowNum = rowNum + 1
        end
    end
    out = out .. '\n|}'
    return out
end

function p.get(frame)
    -- This function will be the main entry point to get the table
    local args = frame.args
    local elements = args.elements or 'all'
    local parts = args.parts or 'all'
    local ops = args.ops or 'all'

    -- Call the getTable function to generate the table
    return p.getTable(frame, elements, parts, ops)
end

function p.all(frame)
    return p.getTable(frame, 'all', 'all', 'all')
end

function p.testInput(frame)
    local args = frame.args
    local out = ''
    for k, v in pairs(args) do
        out = out .. k .. ': ' .. tostring(v) .. '\n'
    end
    return out
end

return p