Edge Rewrite
// HTMLRewriter · presentation

This page was redesigned at the edge.

Cloudflare fetched the original article and streamed it through HTMLRewriter to apply an entirely new visual system without rebuilding the source page.

// request.cf · coarse context

A page that knows where it met you.

Only coarse request metadata is shown. This demo does not display or persist visitor IP addresses.

Country
US
Cloudflare location
CMH
Connection
HTTP/2
Language
Not provided

Ray ID: a237cc5ace13c125

Jump to content

Module:Sandbox/Blippy1998

From Wikipedia, the free encyclopedia
local p = {}

-- Helper to mimic PHP's explode(delimiter, string, 2)
local function split_once(str, delimiter)
    local pos = mw.ustring.find(str, delimiter, 1, true)
    if pos then
        return mw.ustring.sub(str, 1, pos - 1), mw.ustring.sub(str, pos + mw.ustring.len(delimiter))
    end
    return str, nil
end

function p.parseTablesToData(text)
    local lines = mw.text.split(text, "\n")
    
    local parsed_data = {}
    local current_table = nil
    local current_row = nil
    
    for _, outLine in ipairs(lines) do
        local line = mw.text.trim(outLine)
        
        -- Equivalent to skipping via 'continue'
        if line ~= '' then
            local first_char = mw.ustring.sub(line, 1, 1)
            local first_two = mw.ustring.sub(line, 1, 2)
            
            local indent_match, attributes_match = mw.ustring.match(line, "^(:*)%s*%{%|(.*)$")
            
            if indent_match then
                -- Start a new table
                current_table = {
                    attributes = mw.text.unstrip(attributes_match),
                    rows = {}
                }
                table.insert(parsed_data, current_table)
                current_row = nil
                
            elseif not current_table then
                -- Not inside a table, do nothing (skip)
                
            elseif first_two == '|}' then
                -- End the current table
                current_table = nil
                current_row = nil
                
            elseif first_two == '|-' then
                -- Start a new row
                line = mw.ustring.gsub(line, "^|%-+", "")
                current_row = {
                    attributes = mw.text.unstrip(line),
                    cells = {}
                }
                table.insert(current_table.rows, current_row)
                
            elseif first_char == '|' or first_char == '!' or first_two == '|+' then
                -- Process cells, headers, or captions
                
                -- Handle implicit rows (if cell data appears before a |- tag)
                if not current_row and first_two ~= '|+' then
                    current_row = { attributes = "", cells = {} }
                    table.insert(current_table.rows, current_row)
                end
                
                if first_two == '|+' then
                    first_char = '+'
                    line = mw.ustring.sub(line, 3)
                    current_table.caption = mw.text.trim(mw.text.unstrip(line))
                else
                    line = mw.ustring.sub(line, 2)
                    
                    if first_char == '!' then
                        line = mw.ustring.gsub(line, "!!", "||")
                    end
                    
                    local cells = mw.text.split(line, "||", true)
                    
                    for _, cell_str in ipairs(cells) do
                        local cell_type = (first_char == '!') and "th" or "td"
                        local cell_attr_str, cell_content_str = split_once(cell_str, "|")
                        
                        local cell_obj = {
                            type = cell_type,
                            attributes = "",
                            content = ""
                        }
                        
                        -- Replicate PHP's logic to check for [[ links or -{ language converter tags
                        -- to ensure a pipe inside a link isn't mistaken for an attribute delimiter.
                        if not cell_content_str or mw.ustring.match(cell_attr_str, "%[%[") or mw.ustring.match(cell_attr_str, "%-%{") then
                            cell_obj.content = mw.text.trim(cell_str)
                        else
                            cell_obj.attributes = mw.text.unstrip(cell_attr_str)
                            cell_obj.content = mw.text.trim(cell_content_str)
                        end
                        
                        table.insert(current_row.cells, cell_obj)
                    end
                end
            end
        end
    end
    
    return parsed_data
end

function p.testLoadPage(frame)
    -- 1. Define the page title to load. 
    -- Note: Testing this on the full US Reps page immediately will yield a massive dump string.
    -- I recommend creating a subpage with a small test table first.
    local page_title = "List of current United States representatives#List of representatives" 
    
    local titleObj = mw.title.new(page_title)
    if not titleObj then return "Error: Invalid title." end

    -- 2. Fetch the raw wikitext
    local content = titleObj:getContent()
    if not content then return "Error: Page not found or empty." end

    -- 3. Run the parser
    local parsed_data = p.parseTablesToData(content)[6]

    -- 4. Dump the resulting Lua table as a preformatted string so you can read the structure
    return "<pre>\n" .. mw.dumpObject(parsed_data) .. "\n</pre>"
end

function p.tallyParties(frame)
    -- 1. Load the page and parse the text
    local page_title = "List of current United States representatives#List of representatives" 
    local titleObj = mw.title.new(page_title)
    if not titleObj then return "Error: Invalid title." end

    local content = titleObj:getContent()
    if not content then return "Error: Page not found or empty." end

    local parsed_data = p.parseTablesToData(content)[6]
    if not parsed_data then return "Error: Table not found." end

    -- 2. Build a dynamic column map from the header row
    local column_map = {}
    local current_col = 1
    local header_row = parsed_data.rows[1]
    
    for _, cell in ipairs(header_row.cells) do
        -- Clean the header text (removes <ref> tags and hidden spans)
        local header_text = mw.ustring.gsub(cell.content, "<[^>]+>", "")
        header_text = mw.text.trim(header_text)
        
        -- Check if this header spans multiple columns (e.g., colspan=2)
        local colspan = 1
        local colspan_match = mw.ustring.match(cell.attributes, "colspan%s*=%s*[\"']?(%d+)[\"']?")
        if colspan_match then
            colspan = tonumber(colspan_match)
        end
        
        column_map[header_text] = {
            start_index = current_col,
            span = colspan,
            -- For Party, the text name is in the right-most cell of the span
            end_index = current_col + colspan - 1 
        }
        
        current_col = current_col + colspan
    end

    -- Abort if we can't find the Party column
    if not column_map["Party"] then return "Error: Could not find 'Party' column." end
    
    -- Extract the exact index we need to check in the data rows
    local party_col_index = column_map["Party"].end_index

    -- 3. Initialize the tally counters
    local tallies = {
        Democratic = 0,
        Republican = 0,
        Independent = 0,
        Vacant = 0
    }

    -- 4. Iterate through the data rows
    for i = 2, #parsed_data.rows do
        local row = parsed_data.rows[i]
        local cells = row.cells
        
        if #cells > 0 then
            
            -- Check for vacant seats (vacant rows use a massive colspan, yielding fewer cells)
            if #cells < party_col_index then
                assert(#cells == 2, "Row had " .. #cells .. " cells. Expected 2.")
                assert(cells[2].content == "''Vacant''", "Expected ''Vacant'', got: " .. tostring(cells[2].content))
                tallies.Vacant = tallies.Vacant + 1
            else
                -- 5. Extract the party using the dynamic index
                local party = cells[party_col_index].content
                
                party = mw.ustring.gsub(party, "<[^>]+>", "")
                party = mw.text.trim(party)
                
                if tallies[party] ~= nil then
                    tallies[party] = tallies[party] + 1
                else
                    tallies[party] = 1
                end
            end
            
        end
    end

    -- 6. Format the output
    local output = "'''Current House Tallies:'''\n"
    output = output .. "* Democratic: " .. tallies.Democratic .. "\n"
    output = output .. "* Republican: " .. tallies.Republican .. "\n"
    output = output .. "* Independent: " .. tallies.Independent .. "\n"
    output = output .. "* Vacant: " .. tallies.Vacant .. "\n"
    
    return output
end

return p