Mudanças entre as edições de "Módulo:Gb"

De Wiki Gla
Ir para navegação Ir para pesquisar
Linha 1: Linha 1:
local p = {}
local p = {}


function p.render(frame)
-- === Utilidades ===
    local args = frame.args


    local imagem = args.imagem or ""
local function trim(s)
     local titulo = args.titulo or "Título"
     if type(s) ~= "string" then
     local botao  = args.botao or "Ler agora"
        return s
     local link  = args.link or "#"
     end
     return mw.text.trim(s)
end


     -- Container
local function split_list(s)
    local html = mw.html.create("div")
     -- Tenta primeiro por ';' (recomendado quando usar vírgula decimal).
        :css("position", "relative")
    if s:find(";") then
         :css("width", "216px")
         local t = {}
         :css("height", "292px")
         for part in mw.text.gsplit(s, ";", true) do
        :css("border-radius", "14px")
            table.insert(t, part)
         :css("overflow", "hidden")
         end
         :css("font-family", "Arial, sans-serif")
         return t
        :css("color", "#fff")
    end
        :css("box-shadow", "0 6px 18px rgba(0,0,0,.35)")
    -- Caso não haja ';', separa por ',' (útil se números usam ponto decimal).
         :css("background", imagem ~= "" and ("url(" .. imagem .. ") center/cover no-repeat #111") or "#111")
    local t = {}
    for part in mw.text.gsplit(s, ",", true) do
         table.insert(t, part)
    end
    return t
end


    -- Título
local function parse_number(token)
     html:tag("div")
     if type(token) ~= "string" then
        :css("position", "absolute")
         return nil
         :css("left", "12px")
    end
        :css("right", "12px")
    token = trim(token)
        :css("bottom", "70px")
    if token == "" then
        :css("font-size", "16px")
         return nil
         :css("font-weight", "800")
    end
        :wikitext(titulo)


     -- Botão
     -- Remove espaços
html:tag("a")
     token = token:gsub("%s+", "")
    :attr("href", link)
    :css("position", "absolute")
    :css("left", "12px")
    :css("right", "12px")
    :css("bottom", "14px")
    :css("display", "block")
    :css("text-align", "center")
    :css("padding", "10px 12px")
    :css("background", "#1f8b4c")
    :css("color", "#eafff3")
    :css("font-weight", "800")
     :css("font-size", "14px")
    :css("text-decoration", "none")
    :css("border-radius", "10px")
    :wikitext(botao)


    -- Heurística pt-BR:
    -- 1) Se tiver vírgula e ponto, assume '.' como milhar e ',' como decimal
    --    Ex.: "1.234,56" -> "1234.56"
    if token:find(",") and token:find("%.") then
        token = token:gsub("%.", "") -- tira milhares
        token = token:gsub(",", ".") -- vírgula -> ponto decimal
        -- 2) Se só tiver vírgula, assume vírgula decimal
    elseif token:find(",") then
        token = token:gsub(",", ".")
        -- 3) Se só tiver ponto, deixa como está (ponto decimal)
    end


     return tostring(html)
     local n = tonumber(token)
    return n
end
 
local function collect_numbers(frame)
    local args = frame:getParent() and frame:getParent().args or frame.args
    local nums = {}
 
    -- 1) Lista em 'valores='
    local lista = args.valores or args.lista
    if lista and trim(lista) ~= "" then
        for _, part in ipairs(split_list(lista)) do
            local n = parse_number(part)
            if n then
                table.insert(nums, n)
            end
        end
    end
 
    -- 2) Parâmetros posicionais 1,2,3,...
    local i = 1
    while true do
        local v = args[i]
        if v == nil then
            break
        end
        v = trim(v)
        if v and v ~= "" then
            -- Pode ser lista dentro do posicional
            local parts = split_list(v)
            for _, part in ipairs(parts) do
                local n = parse_number(part)
                if n then
                    table.insert(nums, n)
                end
            end
        end
        i = i + 1
    end
 
    return nums
end
 
local function round(n, casas)
    if not casas or casas == "" then
        return n
    end
    casas = tonumber(casas) or 0
    local mult = 10 ^ casas
    if n >= 0 then
        return math.floor(n * mult + 0.5) / mult
    else
        return math.ceil(n * mult - 0.5) / mult
    end
end
 
local function format_number(n, casas, formato)
    n = round(n, casas)
    if formato == "pt" then
        -- Formata com vírgula decimal e ponto de milhar
        local s = string.format("%." .. tostring(tonumber(casas) or 0) .. "f", n)
        -- s usa ponto decimal; converter para pt-BR
        local inteiro, frac = s:match("^(-?%d+)%.(%d+)$")
        if not inteiro then
            inteiro = s
            frac = nil
        end
        -- insere pontos nos milhares
        local k
        local sign = ""
        if inteiro:sub(1, 1) == "-" then
            sign = "-"
            inteiro = inteiro:sub(2)
        end
        while true do
            inteiro, k = inteiro:gsub("^(-?%d+)(%d%d%d)", "%1.%2")
            if k == 0 then
                break
            end
        end
        if frac then
            return sign .. inteiro .. "," .. frac
        else
            return sign .. inteiro
        end
    else
        -- "en" ou padrão: ponto decimal, sem milhar
        local casasN = tonumber(casas) or 0
        return string.format("%." .. tostring(casasN) .. "f", n)
    end
end
 
local function compute(nums, op)
    if #nums == 0 then
        return nil
    end
    if op == "soma" or op == "sum" then
        local s = 0
        for _, v in ipairs(nums) do
            s = s + v
        end
        return s
    elseif op == "media" or op == "média" or op == "avg" then
        local s = 0
        for _, v in ipairs(nums) do
            s = s + v
        end
        return s / #nums
    elseif op == "min" or op == "mín" then
        local m = nums[1]
        for i = 2, #nums do
            if nums[i] < m then
                m = nums[i]
            end
        end
        return m
    elseif op == "max" then
        local m = nums[1]
        for i = 2, #nums do
            if nums[i] > m then
                m = nums[i]
            end
        end
        return m
    elseif op == "contar" or op == "count" then
        return #nums
    else
        -- padrão: soma
        local s = 0
        for _, v in ipairs(nums) do
            s = s + v
        end
        return s
    end
end
 
-- === Interface pública ===
 
function p.calc(frame)
    local args = frame:getParent() and frame:getParent().args or frame.args
 
    local op = (args.op or args.operacao or args.operacao or "soma"):lower()
    local casas = args.casas or args.decimais or 2
    local formato = (args.formato or args.locale or "pt"):lower() -- "pt" ou "en"
 
    local nums = collect_numbers(frame)
    local result = compute(nums, op)
 
    if result == nil then
        return "—" -- sem dados
    end
 
    return format_number(result, casas, formato)
end
end


return p
return p

Edição das 19h35min de 26 de setembro de 2025

A documentação para este módulo pode ser criada em Módulo:Gb/doc

local p = {}

-- === Utilidades ===

local function trim(s)
    if type(s) ~= "string" then
        return s
    end
    return mw.text.trim(s)
end

local function split_list(s)
    -- Tenta primeiro por ';' (recomendado quando usar vírgula decimal).
    if s:find(";") then
        local t = {}
        for part in mw.text.gsplit(s, ";", true) do
            table.insert(t, part)
        end
        return t
    end
    -- Caso não haja ';', separa por ',' (útil se números usam ponto decimal).
    local t = {}
    for part in mw.text.gsplit(s, ",", true) do
        table.insert(t, part)
    end
    return t
end

local function parse_number(token)
    if type(token) ~= "string" then
        return nil
    end
    token = trim(token)
    if token == "" then
        return nil
    end

    -- Remove espaços
    token = token:gsub("%s+", "")

    -- Heurística pt-BR:
    -- 1) Se tiver vírgula e ponto, assume '.' como milhar e ',' como decimal
    --    Ex.: "1.234,56" -> "1234.56"
    if token:find(",") and token:find("%.") then
        token = token:gsub("%.", "") -- tira milhares
        token = token:gsub(",", ".") -- vírgula -> ponto decimal
        -- 2) Se só tiver vírgula, assume vírgula decimal
    elseif token:find(",") then
        token = token:gsub(",", ".")
        -- 3) Se só tiver ponto, deixa como está (ponto decimal)
    end

    local n = tonumber(token)
    return n
end

local function collect_numbers(frame)
    local args = frame:getParent() and frame:getParent().args or frame.args
    local nums = {}

    -- 1) Lista em 'valores='
    local lista = args.valores or args.lista
    if lista and trim(lista) ~= "" then
        for _, part in ipairs(split_list(lista)) do
            local n = parse_number(part)
            if n then
                table.insert(nums, n)
            end
        end
    end

    -- 2) Parâmetros posicionais 1,2,3,...
    local i = 1
    while true do
        local v = args[i]
        if v == nil then
            break
        end
        v = trim(v)
        if v and v ~= "" then
            -- Pode ser lista dentro do posicional
            local parts = split_list(v)
            for _, part in ipairs(parts) do
                local n = parse_number(part)
                if n then
                    table.insert(nums, n)
                end
            end
        end
        i = i + 1
    end

    return nums
end

local function round(n, casas)
    if not casas or casas == "" then
        return n
    end
    casas = tonumber(casas) or 0
    local mult = 10 ^ casas
    if n >= 0 then
        return math.floor(n * mult + 0.5) / mult
    else
        return math.ceil(n * mult - 0.5) / mult
    end
end

local function format_number(n, casas, formato)
    n = round(n, casas)
    if formato == "pt" then
        -- Formata com vírgula decimal e ponto de milhar
        local s = string.format("%." .. tostring(tonumber(casas) or 0) .. "f", n)
        -- s usa ponto decimal; converter para pt-BR
        local inteiro, frac = s:match("^(-?%d+)%.(%d+)$")
        if not inteiro then
            inteiro = s
            frac = nil
        end
        -- insere pontos nos milhares
        local k
        local sign = ""
        if inteiro:sub(1, 1) == "-" then
            sign = "-"
            inteiro = inteiro:sub(2)
        end
        while true do
            inteiro, k = inteiro:gsub("^(-?%d+)(%d%d%d)", "%1.%2")
            if k == 0 then
                break
            end
        end
        if frac then
            return sign .. inteiro .. "," .. frac
        else
            return sign .. inteiro
        end
    else
        -- "en" ou padrão: ponto decimal, sem milhar
        local casasN = tonumber(casas) or 0
        return string.format("%." .. tostring(casasN) .. "f", n)
    end
end

local function compute(nums, op)
    if #nums == 0 then
        return nil
    end
    if op == "soma" or op == "sum" then
        local s = 0
        for _, v in ipairs(nums) do
            s = s + v
        end
        return s
    elseif op == "media" or op == "média" or op == "avg" then
        local s = 0
        for _, v in ipairs(nums) do
            s = s + v
        end
        return s / #nums
    elseif op == "min" or op == "mín" then
        local m = nums[1]
        for i = 2, #nums do
            if nums[i] < m then
                m = nums[i]
            end
        end
        return m
    elseif op == "max" then
        local m = nums[1]
        for i = 2, #nums do
            if nums[i] > m then
                m = nums[i]
            end
        end
        return m
    elseif op == "contar" or op == "count" then
        return #nums
    else
        -- padrão: soma
        local s = 0
        for _, v in ipairs(nums) do
            s = s + v
        end
        return s
    end
end

-- === Interface pública ===

function p.calc(frame)
    local args = frame:getParent() and frame:getParent().args or frame.args

    local op = (args.op or args.operacao or args.operacao or "soma"):lower()
    local casas = args.casas or args.decimais or 2
    local formato = (args.formato or args.locale or "pt"):lower() -- "pt" ou "en"

    local nums = collect_numbers(frame)
    local result = compute(nums, op)

    if result == nil then
        return "—" -- sem dados
    end

    return format_number(result, casas, formato)
end

return p