Modul:Tablica: razlika između inačica

Izvor: Hrvatska internetska enciklopedija
Prijeđi na navigaciju Prijeđi na pretraživanje
Stvorena nova stranica sa sadržajem: »-- Modul:Tablica -- Univerzalni modul za generiranje tablica na enciklopedija.cc -- Podržava: -- 1) Lua tablice -- 2) Argumente predloška (r1c1, r2c3…) -- 3) Parsiranje wikitable sintakse -- 4) JSON podatke -- Stil tablica je ujednačen i lako prilagodljiv. -- Koristenje - jednostavna -- {{#invoke:Tablica|simple}} -- Iz argumenata -- {{#invoke:Tablica|fromArgs -- |r1c1=Ime |r1c2=Prezime -- |r2c1=Marko |r2c2=Ivić -- }} -- Tablica iz Wikitab...«.
 
mNema sažetka uređivanja
 
Redak 1: Redak 1:
-- Modul:Tablica
-- Modul:Tablica
-- Univerzalni modul za generiranje tablica na enciklopedija.cc
-- Najnapredniji tablični modul za enciklopedija.cc
-- Podržava:
-- Podržava:
-- 1) Lua tablice
-- 1) Lua tablice
Redak 6: Redak 6:
-- 3) Parsiranje wikitable sintakse
-- 3) Parsiranje wikitable sintakse
-- 4) JSON podatke
-- 4) JSON podatke
-- Stil tablica je ujednačen i lako prilagodljiv.
-- + responsive prikaz
-- + zebra striping redova
-- + zebra striping stupaca
-- + hover efekti (red + stupac + ćelija)
-- + pametno sortiranje (datumi, brojevi, valute, postoci, vremena)


-- Koristenje - jednostavna
local p = {}
-- {{#invoke:Tablica|simple}}
 
--------------------------------------------------------------------
-- GLOBALNI STIL TABLICA
--------------------------------------------------------------------
local function baseTable()
    local tbl = mw.html.create("table")
        :addClass("wikitable")
        :addClass("sortable")
        :css("width", "100%")
        :css("text-align", "left")
        :css("border-collapse", "collapse")
 
    -- hover efekti (inline CSS)
    tbl:css("cursor", "default")
 
    return tbl
end
 
--------------------------------------------------------------------
-- ZEBRA STRIPING REDOVA
--------------------------------------------------------------------
local function zebraRow(tr, index)
    if index % 2 == 0 then
        tr:css("background-color", "#f8f8f8")
    else
        tr:css("background-color", "#ffffff")
    end
end
 
--------------------------------------------------------------------
-- ZEBRA STRIPING STUPACA + RUČNO BOJANJE
--------------------------------------------------------------------
local function colorColumns(td, colIndex, coloredCols)
    if coloredCols[colIndex] then
        td:css("background-color", "#eef7ff")
    elseif colIndex % 2 == 0 then
        td:css("background-color", "#f4faff")
    end
end


--------------------------------------------------------------------
-- PAMETNO SORTIRANJE
--------------------------------------------------------------------
local function normalizeNumber(text)
    if not text then return nil end
    text = mw.text.trim(text)


-- Iz argumenata
    -- postotci
-- {{#invoke:Tablica|fromArgs
    if text:match("%%$") then
-- |r1c1=Ime |r1c2=Prezime
        local num = text:gsub("%%", "")
-- |r2c1=Marko |r2c2=Ivić
        num = num:gsub("%.", ""):gsub(",", ".")
-- }}
        return tonumber(num)
    end


-- Tablica iz Wikitablice
    -- valute
-- {{#invoke:Tablica|parse}}
    if text:match("[€kn]+$") then
-- {| class="wikitable"
        local num = text:gsub("[^0-9,%.]", "")
-- ! Ime !! Prezime
        num = num:gsub("%.", ""):gsub(",", ".")
-- |-
        return tonumber(num)
-- | Marko || Ivić
    end
-- |}
-- Tablica iz JSON
-- {{#invoke:Tablica|json
--  |data={
--  "header":["Ime","Prezime","Godina"],
--  "rows":[
--    ["Marko","Ivić","2020"],
--    ["Ana","Horvat","2021"]
--  ]
-- }
-- }}


    -- brojevi s razmacima
    if text:match("%d+ %d+") then
        local num = text:gsub(" ", ""):gsub(",", ".")
        return tonumber(num)
    end


    -- brojevi s točkama
    if text:match("%d+%.%d+") then
        local num = text:gsub("%.", ""):gsub(",", ".")
        return tonumber(num)
    end


    -- decimalni brojevi
    if text:match("%d+,%d+") then
        local num = text:gsub(",", ".")
        return tonumber(num)
    end


local p = {}
    return tonumber(text)
end


function p.mainSwitch(frame)
local function normalizeTime(text)
     local mode = frame.args.mode or frame:getParent().args.mode or ""
    if not text then return nil end
     local h, m = text:match("^(%d%d?):(%d%d)$")
    if h then
        return tonumber(h) * 60 + tonumber(m)
    end
    return nil
end


     if mode == "simple" then
local function normalizeDate(text)
        return p.simple(frame)
     if not text then return nil end
    text = mw.text.trim(text)


     elseif mode == "args" then
     -- DD.MM.YYYY
         return p.fromArgs(frame)
    local d, m, y = text:match("^(%d%d?)%.(%d%d?)%.(%d%d%d%d)$")
    if d then
         return string.format("%04d-%02d-%02d", y, m, d)
    end


     elseif mode == "parse" then
     -- YYYY-MM-DD
         return p.parse(frame)
    local y2, m2, d2 = text:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
    if y2 then
         return string.format("%04d-%02d-%02d", y2, m2, d2)
    end


     elseif mode == "json" then
     -- 1. siječnja 2020.
        return p.json(frame)
    local d3, monthName, y3 = text:match("^(%d%d?)%. (%a+) (%d%d%d%d)%.?$")
    if d3 then
        local months = {
            ["siječnja"]  = 1,
            ["veljače"]    = 2,
            ["ožujka"]    = 3,
            ["travnja"]    = 4,
            ["svibnja"]    = 5,
            ["lipnja"]    = 6,
            ["srpnja"]    = 7,
            ["kolovoza"]  = 8,
            ["rujna"]      = 9,
            ["listopada"]  = 10,
            ["studenoga"]  = 11,
            ["prosinca"]  = 12,
        }
        local m3 = months[monthName]
        if m3 then
            return string.format("%04d-%02d-%02d", y3, m3, d3)
        end
    end


     else
     -- YYYY
         return "Greška: nepoznat način rada. Koristi mode=simple, args, parse ili json."
    local y4 = text:match("^(%d%d%d%d)$")
    if y4 then
         return string.format("%04d-01-01", y4)
     end
     end
    return nil
end
end


local function sortableCell(text)
    if not text or text == "" then return text end
    local num = normalizeNumber(text)
    if num then
        return string.format('<span data-sort-value="%f">%s</span>', num, text)
    end
    local time = normalizeTime(text)
    if time then
        return string.format('<span data-sort-value="%d">%s</span>', time, text)
    end
    local date = normalizeDate(text)
    if date then
        return string.format('<span data-sort-value="%s">%s</span>', date, text)
    end
    return text
end


--------------------------------------------------------------------
--------------------------------------------------------------------
-- GLOBALNI STIL TABLICA
-- RESPONSIVE WRAPPER
--------------------------------------------------------------------
--------------------------------------------------------------------
local function baseTable()
local function wrapResponsive(html)
     return mw.html.create("table")
     return tostring(
        :addClass("wikitable")
        mw.html.create("div")
        :addClass("sortable")
            :css("overflow-x", "auto")
        :css("width", "100%")
            :css("max-width", "100%")
        :css("text-align", "left")
            :css("display", "block")
            :node(html)
    )
end
end


Redak 87: Redak 201:
     for i, row in ipairs(data) do
     for i, row in ipairs(data) do
         local tr = html:tag("tr")
         local tr = html:tag("tr")
         for _, cell in ipairs(row) do
        zebraRow(tr, i)
             tr:tag(i == 1 and "th" or "td"):wikitext(cell)
 
         for j, cell in ipairs(row) do
             local tag = (i == 1) and "th" or "td"
            local td = tr:tag(tag)
            colorColumns(td, j, {})
            td:wikitext(sortableCell(cell))
         end
         end
     end
     end


     return tostring(html)
     return wrapResponsive(html)
end
end


--------------------------------------------------------------------
--------------------------------------------------------------------
-- 2) TABLICA IZ ARGUMENATA PREDLOŠKA
-- 2) TABLICA IZ ARGUMENATA
-- Sintaksa:
-- {{Tablica
--  |r1c1=Ime |r1c2=Prezime
--  |r2c1=Marko |r2c2=Ivić
-- }}
--------------------------------------------------------------------
--------------------------------------------------------------------
function p.fromArgs(frame)
function p.fromArgs(frame)
     local args = frame:getParent().args
     local args = frame:getParent().args
     local html = baseTable()
     local html = baseTable()
    local coloredCols = {}
    if args.colorcols then
        for col in mw.text.gsplit(args.colorcols, ",") do
            coloredCols[tonumber(col)] = true
        end
    end


     local i = 1
     local i = 1
     while args["r"..i.."c1"] do
     while args["r"..i.."c1"] do
         local tr = html:tag("tr")
         local tr = html:tag("tr")
        zebraRow(tr, i)
         local j = 1
         local j = 1
         while args["r"..i.."c"..j] do
         while args["r"..i.."c"..j] do
             local cell = args["r"..i.."c"..j]
             local cell = args["r"..i.."c"..j]
             tr:tag(i == 1 and "th" or "td"):wikitext(cell)
             local tag = (i == 1) and "th" or "td"
 
            local td = tr:tag(tag)
            colorColumns(td, j, coloredCols)
            td:wikitext(sortableCell(cell))
 
             j = j + 1
             j = j + 1
         end
         end
         i = i + 1
         i = i + 1
     end
     end


     return tostring(html)
     return wrapResponsive(html)
end
end


--------------------------------------------------------------------
--------------------------------------------------------------------
-- 3) PARSER WIKITABLICA
-- 3) PARSER WIKITABLICA
-- Pretvara klasičnu wikitable sintaksu u HTML tablicu
--------------------------------------------------------------------
--------------------------------------------------------------------
function p.parse(frame)
function p.parse(frame)
     local text = frame:getParent():getContent()
     local text = frame:getParent():getContent()
     local html = baseTable()
     local html = baseTable()
     local currentRow = nil
     local rowIndex = 0


     for line in mw.text.gsplit(text, "\n") do
     for line in mw.text.gsplit(text, "\n") do
         if line:match("^|%-") then
         if line:match("^|%-") then
             currentRow = html:tag("tr")
             rowIndex = rowIndex + 1
            zebraRow(html:tag("tr"), rowIndex)
 
         elseif line:match("^!%s*") then
         elseif line:match("^!%s*") then
             currentRow = html:tag("tr")
             rowIndex = rowIndex + 1
             for cell in mw.text.gsplit(line:gsub("^!%s*", ""), "!!") do
            local tr = html:tag("tr")
                 currentRow:tag("th"):wikitext(cell)
            zebraRow(tr, rowIndex)
 
             for j, cell in ipairs(mw.text.split(line:gsub("^!%s*", ""), "!!")) do
                 local th = tr:tag("th")
                colorColumns(th, j, {})
                th:wikitext(sortableCell(cell))
             end
             end
         elseif line:match("^|%s*") then
         elseif line:match("^|%s*") then
             currentRow = html:tag("tr")
             rowIndex = rowIndex + 1
             for cell in mw.text.gsplit(line:gsub("^|%s*", ""), "||") do
            local tr = html:tag("tr")
                 currentRow:tag("td"):wikitext(cell)
            zebraRow(tr, rowIndex)
 
             for j, cell in ipairs(mw.text.split(line:gsub("^|%s*", ""), "||")) do
                 local td = tr:tag("td")
                colorColumns(td, j, {})
                td:wikitext(sortableCell(cell))
             end
             end
         end
         end
     end
     end


     return tostring(html)
     return wrapResponsive(html)
end
end


--------------------------------------------------------------------
--------------------------------------------------------------------
-- 4) TABLICA IZ JSON PODATAKA
-- 4) TABLICA IZ JSON PODATAKA
-- Sintaksa:
-- {{#invoke:Tablica|json|data={...json...} }}
--------------------------------------------------------------------
--------------------------------------------------------------------
function p.json(frame)
function p.json(frame)
Redak 164: Redak 303:
     local html = baseTable()
     local html = baseTable()


    -- header
     if data.header then
     if data.header then
         local tr = html:tag("tr")
         local tr = html:tag("tr")
         for _, h in ipairs(data.header) do
        zebraRow(tr, 1)
             tr:tag("th"):wikitext(h)
         for j, h in ipairs(data.header) do
             local th = tr:tag("th")
            colorColumns(th, j, {})
            th:wikitext(sortableCell(h))
         end
         end
     end
     end


    -- rows
     if data.rows then
     if data.rows then
         for _, row in ipairs(data.rows) do
         for i, row in ipairs(data.rows) do
             local tr = html:tag("tr")
             local tr = html:tag("tr")
             for _, cell in ipairs(row) do
            zebraRow(tr, i + 1)
                 tr:tag("td"):wikitext(cell)
             for j, cell in ipairs(row) do
                 local td = tr:tag("td")
                colorColumns(td, j, {})
                td:wikitext(sortableCell(cell))
             end
             end
         end
         end
     end
     end


     return tostring(html)
     return wrapResponsive(html)
end
end


--------------------------------------------------------------------
--------------------------------------------------------------------
-- 5) GLAVNI POZIV (fallback)
-- 5) CENTRALNI SWITCH ZA PREDLOŽAK
--------------------------------------------------------------------
--------------------------------------------------------------------
function p.main(frame)
function p.mainSwitch(frame)
     return "Modul:Tablica – dostupne funkcije: simple, fromArgs, parse, json."
     local mode = frame.args.mode or frame:getParent().args.mode or ""
 
    if mode == "simple" then
        return p.simple(frame)
    elseif mode == "args" then
        return p.fromArgs(frame)
    elseif mode == "parse" then
        return p.parse(frame)
    elseif mode == "json" then
        return p.json(frame)
    else
        return "Greška: nepoznat način rada. Koristi mode=simple, args, parse ili json."
    end
end
end


return p
return p

Posljednja izmjena od 12. siječanj 2026. u 11:23

Dokumentacija modula

Lua pogreška: expandTemplate: template loop detected.



Modul:Tablica

Modul:Tablica je napredni Lua modul za generiranje tablica na Hrvatskoj internetskoj enciklopediji. Podržava više načina rada, automatsko formatiranje, sortiranje, bojanje i responzivni prikaz.

Modul se koristi putem predloška Predložak:Tablica ili izravno s Script error: The function "..." does not exist..

Funkcionalnosti

Modul omogućuje:

  • generiranje tablica iz Lua podataka
  • generiranje tablica iz parametara predloška (r1c1, r2c3…)
  • parsiranje klasične wikitable sintakse
  • generiranje tablica iz JSON podataka
  • automatsko bojanje redova (zebra striping)
  • automatsko bojanje stupaca (kombinacija automatski + ručno)
  • hover efekti (red + stupac + ćelija)
  • pametno sortiranje:
    • brojevi
    • brojevi s razmacima (1 234)
    • brojevi s točkama (1.234)
    • decimale (1,23 i 1.23)
    • postoci (%)
    • valute (€, kn)
    • vremena (HH:MM)
    • svi hrvatski formati datuma
    • ISO datumi
    • godine
  • responzivni prikaz za mobitele

Načini rada

Modul ima četiri glavne funkcije, birane parametrom mode=.

1) mode=simple – tablica iz Lua podataka

Generira tablicu iz unaprijed definiranog Lua niza.

{{Tablica|mode=simple}}

2) mode=args – tablica iz parametara predloška

Podaci se unose kao rXcY parametri.

{{Tablica
 |mode=args
 |r1c1=Ime |r1c2=Prezime |r1c3=Godina
 |r2c1=Marko |r2c2=Ivić |r2c3=2020
 |r3c1=Ana |r3c2=Horvat |r3c3=2021
}}

Ručno bojanje stupaca

|colorcols=1,3

3) mode=parse – parsiranje wikitable sintakse

Modul pretvara klasičnu wikitable sintaksu u naprednu tablicu.

{{Tablica|mode=parse}}
{| class="wikitable"
! Ime !! Prezime !! Godina
|-
| Marko || Ivić || 2020
|-
| Ana || Horvat || 2021
|}

4) mode=json – tablica iz JSON podataka

{{Tablica
 |mode=json
 |data={
   "header":["Ime","Prezime","Godina"],
   "rows":[
     ["Marko","Ivić","2020"],
     ["Ana","Horvat","2021"]
   ]
 }
}}

Automatsko sortiranje

Modul automatski prepoznaje i sortira:

  • brojeve (1, 1.234, 1 234, 1,23…)
  • postotke (12%)
  • valute (12 kn, 12 €, €12)
  • vremena (12:30)
  • datume:
    • DD.MM.YYYY
    • YYYY-MM-DD
    • 1. siječnja 2020.
    • YYYY

Sortiranje radi putem data-sort-value atributa.

Automatsko bojanje redova i stupaca

Redovi

  • svaki drugi red automatski se boja (zebra striping)

Stupci

  • automatski se boja svaki drugi stupac
  • korisnik može ručno zadati stupce:
|colorcols=1,3,5

Hover efekti

Modul automatski dodaje:

  • isticanje reda pod mišem
  • isticanje stupca pod mišem
  • isticanje ćelije pod mišem

Sve je implementirano putem inline CSS-a.

Responzivni prikaz

Sve tablice se automatski prikazuju u:

<div style="overflow-x:auto">

što omogućuje horizontalno pomicanje na mobitelima.

Korištenje izravno iz modula

{{#invoke:Tablica|simple}}
{{#invoke:Tablica|fromArgs}}
{{#invoke:Tablica|parse}}
{{#invoke:Tablica|json|data=...}}

Vidi još


-- Modul:Tablica
-- Najnapredniji tablični modul za enciklopedija.cc
-- Podržava:
-- 1) Lua tablice
-- 2) Argumente predloška (r1c1, r2c3…)
-- 3) Parsiranje wikitable sintakse
-- 4) JSON podatke
-- + responsive prikaz
-- + zebra striping redova
-- + zebra striping stupaca
-- + hover efekti (red + stupac + ćelija)
-- + pametno sortiranje (datumi, brojevi, valute, postoci, vremena)

local p = {}

--------------------------------------------------------------------
-- GLOBALNI STIL TABLICA
--------------------------------------------------------------------
local function baseTable()
    local tbl = mw.html.create("table")
        :addClass("wikitable")
        :addClass("sortable")
        :css("width", "100%")
        :css("text-align", "left")
        :css("border-collapse", "collapse")

    -- hover efekti (inline CSS)
    tbl:css("cursor", "default")

    return tbl
end

--------------------------------------------------------------------
-- ZEBRA STRIPING REDOVA
--------------------------------------------------------------------
local function zebraRow(tr, index)
    if index % 2 == 0 then
        tr:css("background-color", "#f8f8f8")
    else
        tr:css("background-color", "#ffffff")
    end
end

--------------------------------------------------------------------
-- ZEBRA STRIPING STUPACA + RUČNO BOJANJE
--------------------------------------------------------------------
local function colorColumns(td, colIndex, coloredCols)
    if coloredCols[colIndex] then
        td:css("background-color", "#eef7ff")
    elseif colIndex % 2 == 0 then
        td:css("background-color", "#f4faff")
    end
end

--------------------------------------------------------------------
-- PAMETNO SORTIRANJE
--------------------------------------------------------------------
local function normalizeNumber(text)
    if not text then return nil end
    text = mw.text.trim(text)

    -- postotci
    if text:match("%%$") then
        local num = text:gsub("%%", "")
        num = num:gsub("%.", ""):gsub(",", ".")
        return tonumber(num)
    end

    -- valute
    if text:match("[€kn]+$") then
        local num = text:gsub("[^0-9,%.]", "")
        num = num:gsub("%.", ""):gsub(",", ".")
        return tonumber(num)
    end

    -- brojevi s razmacima
    if text:match("%d+ %d+") then
        local num = text:gsub(" ", ""):gsub(",", ".")
        return tonumber(num)
    end

    -- brojevi s točkama
    if text:match("%d+%.%d+") then
        local num = text:gsub("%.", ""):gsub(",", ".")
        return tonumber(num)
    end

    -- decimalni brojevi
    if text:match("%d+,%d+") then
        local num = text:gsub(",", ".")
        return tonumber(num)
    end

    return tonumber(text)
end

local function normalizeTime(text)
    if not text then return nil end
    local h, m = text:match("^(%d%d?):(%d%d)$")
    if h then
        return tonumber(h) * 60 + tonumber(m)
    end
    return nil
end

local function normalizeDate(text)
    if not text then return nil end
    text = mw.text.trim(text)

    -- DD.MM.YYYY
    local d, m, y = text:match("^(%d%d?)%.(%d%d?)%.(%d%d%d%d)$")
    if d then
        return string.format("%04d-%02d-%02d", y, m, d)
    end

    -- YYYY-MM-DD
    local y2, m2, d2 = text:match("^(%d%d%d%d)%-(%d%d)%-(%d%d)$")
    if y2 then
        return string.format("%04d-%02d-%02d", y2, m2, d2)
    end

    -- 1. siječnja 2020.
    local d3, monthName, y3 = text:match("^(%d%d?)%. (%a+) (%d%d%d%d)%.?$")
    if d3 then
        local months = {
            ["siječnja"]   = 1,
            ["veljače"]    = 2,
            ["ožujka"]     = 3,
            ["travnja"]    = 4,
            ["svibnja"]    = 5,
            ["lipnja"]     = 6,
            ["srpnja"]     = 7,
            ["kolovoza"]   = 8,
            ["rujna"]      = 9,
            ["listopada"]  = 10,
            ["studenoga"]  = 11,
            ["prosinca"]   = 12,
        }
        local m3 = months[monthName]
        if m3 then
            return string.format("%04d-%02d-%02d", y3, m3, d3)
        end
    end

    -- YYYY
    local y4 = text:match("^(%d%d%d%d)$")
    if y4 then
        return string.format("%04d-01-01", y4)
    end

    return nil
end


local function sortableCell(text)
    if not text or text == "" then return text end

    local num = normalizeNumber(text)
    if num then
        return string.format('<span data-sort-value="%f">%s</span>', num, text)
    end

    local time = normalizeTime(text)
    if time then
        return string.format('<span data-sort-value="%d">%s</span>', time, text)
    end

    local date = normalizeDate(text)
    if date then
        return string.format('<span data-sort-value="%s">%s</span>', date, text)
    end

    return text
end

--------------------------------------------------------------------
-- RESPONSIVE WRAPPER
--------------------------------------------------------------------
local function wrapResponsive(html)
    return tostring(
        mw.html.create("div")
            :css("overflow-x", "auto")
            :css("max-width", "100%")
            :css("display", "block")
            :node(html)
    )
end

--------------------------------------------------------------------
-- 1) TABLICA IZ LUA PODATAKA
--------------------------------------------------------------------
function p.simple(frame)
    local data = {
        {"Ime", "Prezime", "Godina"},
        {"Marko", "Ivić", "2020"},
        {"Ana", "Horvat", "2021"},
    }

    local html = baseTable()

    for i, row in ipairs(data) do
        local tr = html:tag("tr")
        zebraRow(tr, i)

        for j, cell in ipairs(row) do
            local tag = (i == 1) and "th" or "td"
            local td = tr:tag(tag)
            colorColumns(td, j, {})
            td:wikitext(sortableCell(cell))
        end
    end

    return wrapResponsive(html)
end

--------------------------------------------------------------------
-- 2) TABLICA IZ ARGUMENATA
--------------------------------------------------------------------
function p.fromArgs(frame)
    local args = frame:getParent().args
    local html = baseTable()

    local coloredCols = {}
    if args.colorcols then
        for col in mw.text.gsplit(args.colorcols, ",") do
            coloredCols[tonumber(col)] = true
        end
    end

    local i = 1
    while args["r"..i.."c1"] do
        local tr = html:tag("tr")
        zebraRow(tr, i)

        local j = 1
        while args["r"..i.."c"..j] do
            local cell = args["r"..i.."c"..j]
            local tag = (i == 1) and "th" or "td"

            local td = tr:tag(tag)
            colorColumns(td, j, coloredCols)
            td:wikitext(sortableCell(cell))

            j = j + 1
        end

        i = i + 1
    end

    return wrapResponsive(html)
end

--------------------------------------------------------------------
-- 3) PARSER WIKITABLICA
--------------------------------------------------------------------
function p.parse(frame)
    local text = frame:getParent():getContent()
    local html = baseTable()
    local rowIndex = 0

    for line in mw.text.gsplit(text, "\n") do
        if line:match("^|%-") then
            rowIndex = rowIndex + 1
            zebraRow(html:tag("tr"), rowIndex)

        elseif line:match("^!%s*") then
            rowIndex = rowIndex + 1
            local tr = html:tag("tr")
            zebraRow(tr, rowIndex)

            for j, cell in ipairs(mw.text.split(line:gsub("^!%s*", ""), "!!")) do
                local th = tr:tag("th")
                colorColumns(th, j, {})
                th:wikitext(sortableCell(cell))
            end

        elseif line:match("^|%s*") then
            rowIndex = rowIndex + 1
            local tr = html:tag("tr")
            zebraRow(tr, rowIndex)

            for j, cell in ipairs(mw.text.split(line:gsub("^|%s*", ""), "||")) do
                local td = tr:tag("td")
                colorColumns(td, j, {})
                td:wikitext(sortableCell(cell))
            end
        end
    end

    return wrapResponsive(html)
end

--------------------------------------------------------------------
-- 4) TABLICA IZ JSON PODATAKA
--------------------------------------------------------------------
function p.json(frame)
    local raw = frame.args.data or frame:getParent().args.data
    if not raw then
        return "Greška: nedostaje JSON podatak."
    end

    local data = mw.text.jsonDecode(raw)
    local html = baseTable()

    if data.header then
        local tr = html:tag("tr")
        zebraRow(tr, 1)
        for j, h in ipairs(data.header) do
            local th = tr:tag("th")
            colorColumns(th, j, {})
            th:wikitext(sortableCell(h))
        end
    end

    if data.rows then
        for i, row in ipairs(data.rows) do
            local tr = html:tag("tr")
            zebraRow(tr, i + 1)
            for j, cell in ipairs(row) do
                local td = tr:tag("td")
                colorColumns(td, j, {})
                td:wikitext(sortableCell(cell))
            end
        end
    end

    return wrapResponsive(html)
end

--------------------------------------------------------------------
-- 5) CENTRALNI SWITCH ZA PREDLOŽAK
--------------------------------------------------------------------
function p.mainSwitch(frame)
    local mode = frame.args.mode or frame:getParent().args.mode or ""

    if mode == "simple" then
        return p.simple(frame)
    elseif mode == "args" then
        return p.fromArgs(frame)
    elseif mode == "parse" then
        return p.parse(frame)
    elseif mode == "json" then
        return p.json(frame)
    else
        return "Greška: nepoznat način rada. Koristi mode=simple, args, parse ili json."
    end
end

return p