Va ô cuntinutu

Mòdulu:Bozza/GianAntonucci/Tèssira

Dâ Wikipedia, la nciclupidìa lìbbira.

Mòdulu:Bozza/GianAntonucci/Tèssira è u mòdulu mastru dû sistema di tèssiri (infobox, 'n ingrisi) dâ Wikipedia 'n sicilianu. I mudeḍḍi criati cu stu mòdulu si lìjanu a Wikidata e suppòrtanu assai funzioni avanzati.

Comu funziona

[cancia lu còdici]

U mòdulu esporta a funzioni stampa, chi:

  1. elàbbura i campi dû mudeḍḍu;
  2. càrrica a ntità Wikidata, quannu l'utenti a metti;
  3. ricupigghia i dati di Wikidata c'ammàncanu;
  4. crìa l'HTML dâ tèssira cu TemplateStyles.

Ô carricari di na ntità Wikidata, i so prupità ("P18", pi diri) s'ùsanu pi menzu dû marcaturi @@...@@. Talìa l'esempiu cca sutta.

Esempiu basi basi

[cancia lu còdici]
folklore
Giufà
Una nni penza e centu nni fa
N'abbirtenza...
Minutagghi
Cu' è?pirsunaggiu dû folklore
Gènirimàsculu
Carattarìstichi
  • È babbu
  • Ê voti è spertu
Cunti
Chiḍḍa di Giufà e a portaQuannu so matri ci dissi mi si tira a porta prima mi nesci, iḍḍu sâ scippau e sâ carricau 'n coḍḍu.
Talìa macari: Giufà
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Wikidata = Q1262145
| Supra = ''folklore''
| Tìtulu = Giufà
| Suttatìtulu = Una nni penza e centu nni fa
| Abbirtenza1 = N'abbirtenza...
| Gruppu1 = Minutagghi
| Vuci1 = Cu' è?
| Valuri1 = @@P31@@
| Vuci2 = Gèniri
| Valuri2 = @@P21@@
| Vuci3 = Carattarìstichi
| Valuri3 =
* È babbu
* Ê voti è spertu
| Gruppu4 = Cunti
| Vuci4 = Chiḍḍa di Giufà e a porta
| Valuri4 = Quannu so matri ci dissi mi si tira a porta prima mi nesci, iḍḍu sâ scippau e sâ carricau 'n coḍḍu.
| Sutta = Talìa macari: [[Giufà]]
}}

I campi di sistema

[cancia lu còdici]
Paràmitru Spiecu Pridifinutu
èFigghia Siḍḍu è nchiujuta dintra a n'autra. Voli "Se" o nenti.
Wikidata ID dâ ntità Wikidata unni s'ànn'a pigghiari i dati (pi scempru, Q12345). Siḍḍu è misu, ma vacanti (Wikidata=), nun càrrica nenti. Ntità currenti
SenzaCurrenti Nun fa cùrriri u testu ntunn'â tèssira. Voli "Se" o nenti.
Stili Stile CSS. Voli na stringa. "tessira"
StiliARingu Stili CSS a ringu. Voli na stringa.
Arrivisiona Abbìlita a mudalità p'arrisòrbiri i prubblemi. Voli "Se" o nenti.

Ntâ mudalità Arrivisiona, u mòdulu paraggia tutti i paràmitri usati (comu Tìtulu=, Vuci1=, ecc.) câ so lista dî paràmitri vàliti.

I campi dâ struttura

[cancia lu còdici]
Paràmitru Spiecu Pridifinutu
Tìtulu Tìtulu dâ tèssira
Suttatìtulu Suttatìtulu
Supra Testu supr'â tèssira
Sutta Testu sutt'â tèssira
PediPàggina Noti ô pedi dâ pàggina
NomuMudeḍḍu Nomu dû mudeḍḍu lijatu
LijamiWikidata Fa' vìdiri a lijami a Wikidata. Voli "Se" o nenti.

Siḍḍu LijamiWikidata nun cc'è propia, Tèssira ammuccia a lijami passànnuci nowd=1 a Mudeḍḍu:Lijami sinòtticu.

I campi dî mmàggini

[cancia lu còdici]
Paràmitru Spiecu Pridifinutu
MmàgginiSupra A mmàggini mastra P18
DidascalìaMmàgginiSupra A didascalìa di MmàgginiSupra
MmàgginiSutta A mmàggini sutta
DidascalìaMmàgginiSutta A didascalìa di MmàgginiSutta
MmàgginiManuManca A mmàggini a manu manca
DidascalìaMmàgginiManuManca A didascalìa di MmàgginiManuManca
MmàgginiManuDritta Mmàggini a dritta
DidascalìaMmàgginiManuDritta A didascalìa di MmàgginiManuDritta

I campi dî dati

[cancia lu còdici]
Schema Spiecu Scempru
Vuci[N] Tichetta Vuci1 = Natalizziu
Valuri[N] Cuntinutu Valuri1 = 8 di jinnaru 1921
Gruppu[N] Sizzioni Gruppu1 = Dati pirsunali
Prupità[N] Prupità Wikidata Prupità1 = P569
Classi[N] Classi CSS Classi1 = plainlist
Abbirtenza[N] Abbirtenza Abbirtenza1 = Storia

U paràmitru Prupità[N] pirmetti ôn mudeḍḍu spicializzatu di sapiri a chi prupità Wikidata è lijatu un campu, quannu l'utenti nun u dici. Pi diri, pigghiamu un mudeḍḍu comu TèssiraCristianu:

  1. U mudeḍḍu sapi c'u campu Natalizziu currispunni â prupità P569 di Wikidata:
    • Vuci5 = "Natalizziu"
    • Prupità5 = "P569"
  2. Appoi cuntrolla: L'utenti marcau un valuri pi Natalizziu?
    • Se: Usa u valuri lucali: Valuri5 = "8 di jinnaru 1921".
    • No: Usa Prupità5 pi pigghiari u valuri di Wikidata e u metti nta Valuri5.
  3. A stu puntu, TèssiraCristianu passa Vuci5 e Valuri5 a Tèssira.

I mudeḍḍi chi ùsanu stu mòdulu

[cancia lu còdici]

Canciari u stili dî listi

[cancia lu còdici]
Nurmali
  • A
  • B
  • C
Sìmplici
  • A
  • B
  • C
Urizzuntali
  • A
  • B
  • C
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Vuci1 = Lista nurmali
| Valuri1 =
* A
* B
* C
| Vuci2 = Lista sìmplici
| Valuri2 =
* A
* B
* C
| Classi2 = plainlist
| Vuci3 = Lista urizzuntali
| Valuri3 =
* A
* B
* C
| Classi3 = hlist
}}

Tèssira vacanti

[cancia lu còdici]
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Tìtulu =
| Valuri1 =
}}

Valuri vacanti

[cancia lu còdici]
Vuci 3Valuri
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Tìtulu = Stringhi vacanti
| Vuci1 = Vuci 1 (vacanti)
| Valuri1 = 
| Vuci2 = Vuci 1 (sulu spazzi)
| Valuri2 =    
| Vuci3 = Vuci 3
| Valuri3 = Valuri
}}

Testu sulu supra e sutta

[cancia lu còdici]
Testu supra (o supratìtulu)
Testu sutta (o pedi di pàggina)
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Supra = Testu supra
| Sutta = Testu sutta
}}

Nchiùjiri du' tèssiri una dintra a n'autra

[cancia lu còdici]
Tèssira matri
Vuci dâ tèssira matriDati dâ tèssira matri
Vuci dâ tèssira figghia
Tèssira figghia
Vuci dâ tèssira figghiaDati dâ tèssira figghia
Autra vuci dâ tèssira matriAutri dati dâ tèssira matri
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Tìtulu = Tèssira matri
| Vuci1 = Vuci dâ tèssira matri
| Valuri1 = Dati dâ tèssira matri
| Vuci2 = Vuci dâ tèssira figghia
| Valuri2 =
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
 | èFigghia = Se
 | Tìtulu = Tèssira figghia
 | Vuci1 = Vuci dâ tèssira figghia
 | Valuri1 = Dati dâ tèssira figghia
}}
| Vuci3 = Autra vuci dâ tèssira matri
| Valuri3 = Autri dati dâ tèssira matri
}}

Rifirenzi e catijurìi

[cancia lu còdici]
Vuci 1Valuri 1[1]
Vuci 2Valuri 2
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Vuci1 = Vuci 1
| Valuri1 = Valuri 1<ref>I rifirenzi e i catijurìi stannu fora dâ tèssira, â fini dâ pàggina.</ref>[[Catigurìa:Prova di Tèssira]]
| Vuci2 = Vuci 2
| Valuri2 = Valuri 2
}}

Valuri senza tichetta

[cancia lu còdici]
Valuri senza tichetta (pigghia dui culonni)
TichettaDati
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Valuri1 = Valuri senza tichetta (pigghia dui culonni)
| Vuci2 = Tichetta
| Valuri2 = Dati
}}

Gruppi (e nùmmari auti)

[cancia lu còdici]
Gruppi 1, 2 e 50
Gruppu 1
AValuri A
BValuri B
Gruppu 2
CValuri C
Gruppu 50
Ogni ficateḍḍu di musca fa sustanza.
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Tìtulu = Gruppi 1, 2 e 50
| Gruppu1 = Gruppu 1
| Vuci1 = A
| Valuri1 = Valuri A
| Vuci2 = B
| Valuri2 = Valuri B
| Gruppu3 = Gruppu 2
| Vuci3 = C
| Valuri3 = Valuri C
| Gruppu50 = Gruppu 50
| Valuri50 = ''Ogni ficateḍḍu di musca fa sustanza.''
}}

Mèttiri i mmàggini

[cancia lu còdici]
Tìtulu
U Muncibbeḍḍu
A TrinacriaNa cassata
U Tiatru Màssimu di Palermu
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Tìtulu = Tìtulu
| MmàgginiSupra = Mount_Etna.jpg
| DidascalìaMmàgginiSupra = U Muncibbeḍḍu
| MmàgginiManuManca = Trinacria.jpg
| DidascalìaMmàgginiManuManca = A Trinacria
| MmàgginiManuDritta = Cassata_siciliana.jpg
| DidascalìaMmàgginiManuDritta = Na cassata
| MmàgginiSutta = Teatro_Massimo_Palermo.jpg
| DidascalìaMmàgginiSutta = U Tiatru Màssimu di Palermu
}}

Astrajuta autumàtica di Wikidata

[cancia lu còdici]
Albert Einstein
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Wikidata = Q937
| Tìtulu = Albert Einstein
}}

Wikidata sdisabbilitatu

[cancia lu còdici]

Ô mèttiri Wikidata= ma vacanti, nun si càrrica nuḍḍa nfurmazzioni di Wikidata, nimmancu dâ pàggina currenti.

Archimedes (Q8739)
Gèniri@@P21@@
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Wikidata =
| Tìtulu = Archimedes (Q8739)
| Vuci1 = Gèniri
| Valuri1 = @@P21@@
}}

Senza stili pridifinutu

[cancia lu còdici]
Tìtulu
VuciValuri
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Stili = No
| Tìtulu = Tìtulu
| Vuci1 = Vuci
| Valuri1 = Valuri
}}

Canciari stili a ringu

[cancia lu còdici]
VuciValuri
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| StiliARingu = background-color: #eaf3ff; border: 2px dashed #0066cc;
| Vuci1 = Vuci
| Valuri1 = Valuri
}}

Arrivisiona

[cancia lu còdici]
Paràmitru vàlituValuri
Accura! Certi paràmitri nun si pòttiru arricanùsciri: ParàmitruSenzaVàlitu
{{#invoke:Bozza/GianAntonucci/Tèssira|stampa
| Arrivisiona = Se
| Vuci1 = Paràmitru vàlitu
| Valuri1 = Valuri
| ParàmitruSenzaVàlitu = Chistu aviss'a cumpàriri ntâ rivisioni
}}

I sbagghi cchiù cumuni

[cancia lu còdici]

Quannu u mòdulu:

  • nun arricanusci/fa vìdiri certi paràmitri, junci Arrivisiona = Se pi vìdiri quali;
  • nun càrrica Wikidata, cuntrolla chi l'ID Wikidata àvi statu scrivutu bonu (pi diri, "Q12345") e chi nun è vacanti (Wikidata=);
  • nun furmatta certi listi, cuntrolla chi cc'è nu spazziu doppu a stiḍḍuzza: * Item.

  1. I rifirenzi e i catijurìi stannu fora dâ tèssira, â fini dâ pàggina.
local p = {}
local mw = require('mw')

--------------------------------------------------------------------------------
-- 1) VARIÀBBILI D'AJUTU P'ARRICANÙSCIRI I CATIJURÌI E I RIFIRENZI
--------------------------------------------------------------------------------

-- Pattern pî catijurìi
local patternCatijuriiMinusculu = '%[%[%s*category%s*:[^]]*%]%]'

-- Pattern pî rifirenzi (i tichetti <ref>)
local patternRifirenzi = {
    '%<ref[^>]*>.-%</ref%>',  -- Chiḍḍi nurmali
    '%<ref[^/>]*/%>'          -- Chiḍḍi chi si chiùjinu suli
}

--------------------------------------------------------------------------------
-- 2) PIRCURSI CSS PRIDIFINUTI
--------------------------------------------------------------------------------

-- local PIRCURSU_CSS_PRIDIFINITU = "Mudeḍḍu:Tèssira/stili.css"
-- local PIRCURSU_CSS_LISTA_SIMPLICI = "Mudeḍḍu:ListaSìmplici/stili.css"
-- local PIRCURSU_CSS_LISTA_URIZZUNTALI = "Mudeḍḍu:ListaUrizzuntali/stili.css"
local PIRCURSU_CSS_PRIDIFINITU = "Utenti:GianAntonucci/Bozza/Mudeḍḍu:Tèssira/stili.css"
local PIRCURSU_CSS_LISTA_SIMPLICI = "Utenti:GianAntonucci/Bozza/Mudeḍḍu:ListaSìmplici/stili.css"
local PIRCURSU_CSS_LISTA_URIZZUNTALI = "Utenti:GianAntonucci/Bozza/Mudeḍḍu:ListaUrizzuntali/stili.css"

--------------------------------------------------------------------------------
-- 3) FUNZIONI D'AJUTU
--------------------------------------------------------------------------------

-- Sta funzioni pigghia u megghiu valuri di na prupità di na ntità di Wikidata
local function pigghiaValuriWikidata(ntitaWikidata, prupita)
    local successu, rinescitu = pcall(function()
        if not ntitaWikidata or not ntitaWikidata.claims or not ntitaWikidata.claims[prupita] then
            return nil
        end
        
        -- Addifinemu a tabeḍḍa c'àvi tutti i dichiari dâ prupità c'addumannammu
        local tuttiLiDichiari = ntitaWikidata.claims[prupita]
        
        local laMegghiuDichiara = nil
        local luMegghiuRancuNummaru = nil
        
        -- Annumiramu i ranchi chi usa Wikidata
        local abbersuRanchi = {
            preferred = 3,
            normal = 2,
            deprecated = 1
        }
        
        -- Cuntrullamu tutti i dichiari dâ lista chi pigghiammu di Wikidata
        for _, dichiara in ipairs(tuttiLiDichiari) do
            local rancu = dichiara.rank or "normal"
            local rancuNummaru = abbersuRanchi[rancu] or 2
            
            if not luMegghiuRancuNummaru or rancuNummaru > luMegghiuRancuNummaru then
                laMegghiuDichiara = dichiara
                luMegghiuRancuNummaru = rancuNummaru
            end
        end
        
        -- Astrajemu u rancu cchiù autu
        if laMegghiuDichiara and laMegghiuDichiara.mainsnak then
            return mw.wikibase.renderSnak(laMegghiuDichiara.mainsnak)
        end
    end)
    
    -- Siḍḍu a pcall sfallìu, arriggistramu u sbagghiu
    if not successu then
        mw.log("Sbagghiu di Wikidata pâ prupità " .. prupita .. ": " .. tostring(rinescitu))
    end
    
    return successu and rinescitu or nil
end

-- Sta funzioni cuntrolla siḍḍu na stringa è vacanti, livannu i tichetti dî
-- rifirenzi e i lijami dî catijurìi
local function eVacantiLivannuRifirenziECatijurii(valuri)
    if not valuri or valuri == "" then
        return true
    end
    
    -- Cummirtemu tutta a stringa 'n minùsculu
    local valuriMinusculu = mw.ustring.lower(valuri)
    
    -- Livamu i catijurìi e i rifirenzi
    local valuriPulizziatu = mw.ustring.gsub(valuriMinusculu, patternCatijuriiMinusculu, '')
    for _, pattern in ipairs(patternRifirenzi) do
        valuriPulizziatu = mw.ustring.gsub(valuriPulizziatu, pattern, '')
    end
    
    -- S'arrèstanu sulu spazzi janchi, va bonu
    return valuriPulizziatu:match('^%s*$') ~= nil
end

-- Sta funzioni cuntrolla siḍḍu i listi ànnu u furmatu giustu pi stari dintra a
-- l'autri elimenti (comu, pi diri, i ceḍḍi di na tabeḍḍa)
local function cuntrollaLista(valuri, classiCSS)
    if not valuri then
        return valuri
    end
    
    -- Pigghiamu u primu caràttari dâ stringa e videmu siḍḍu è un marcaturi di lista
    local primuCarattari = mw.ustring.sub(valuri, 1, 1)
    if primuCarattari == '#' or primuCarattari == '*' then
        -- Nchiujèmulu ntôn div
        return '<div>\n' .. valuri .. '\n</div>\n'
    end
    
    -- Vasinnò, juncemu sulu n'a-capu
    return valuri .. '\n'
end

-- Sta funzioni cuntrolla siḍḍu un paràmitru àvi un nomu canusciutu
local function eParamitruCanusciutu(nomuParamitru)
	if type(nomuParamitru) ~= 'string' then
		return true
	end
	
	-- Cuntrullamu i paràmitri basi
    local nomaParamitriBasi = {
        "Wikidata", "èFigghia", "SenzaCurrenti", "Stili", "StiliARingu", "Arrivisiona",
        "Tìtulu", "Suttatìtulu", "Supra", "Sutta", "NomuMudeḍḍu", 
        "LijamiWikidata", "PediPàggina", "MmàgginiSupra", "MmàgginiSutta",
        "MmàgginiManuManca", "MmàgginiManuDritta", "DidascalìaMmàgginiSupra",
        "DidascalìaMmàgginiSutta", "DidascalìaMmàgginiManuManca", 
        "DidascalìaMmàgginiManuDritta"
    }
    for _, nomuParamitruBasi in ipairs(nomaParamitriBasi) do
        if nomuParamitru == nomuParamitruBasi then
        	return true
        end
    end
    
    -- Cuntrullamu i paràmitri chî nùmmari
    if nomuParamitru:match("^Abbirtenza%d+$") or
       nomuParamitru:match("^Vuci%d+$") or
       nomuParamitru:match("^Valuri%d+$") or
       nomuParamitru:match("^Gruppu%d+$") or
       nomuParamitru:match("^Prupità%d+$") or
       nomuParamitru:match("^Classi%d+$") then
        return true
    end
    
    return false
end

-- Function to process Wikidata property markers
local function processWikidataMarkers(text, wikidataId)
    if not text or not wikidataId or wikidataId == "" then
        return text
    end
    
    -- Get the frame once
    local frame = mw.getCurrentFrame()
    
    -- Match patterns like @@P21@@, @@P21|label@@, etc.
    text = text:gsub('@@(P%d+)([^@]*)@@', function(property, options)
        -- Build the invoke string
        local invokeString = string.format(
            "{{#invoke:Bozza/GianAntonucci/Wikidata|getProperty|property=%s|from=%s",
            property,
            wikidataId
        )
        
        -- Add formatting options if specified
        if options and options ~= "" then
            options = options:gsub("^|", "")
            if options == "label" then
                invokeString = invokeString .. "|formatting=label"
            elseif options == "raw" then
                invokeString = invokeString .. "|formatting=raw"
            elseif options:match("separator=") then
                local sep = options:match("separator=([^|]+)")
                invokeString = invokeString .. "|separator=" .. sep
            end
        end
        
        invokeString = invokeString .. "}}"
        
        -- Use preprocess to expand the invoke
        local success, result = pcall(function()
            return frame:preprocess(invokeString)
        end)
        
        if success and result and result ~= "" then
            return result
        else
            return "" -- Return empty on error
        end
    end)
    
    -- Also support @@LABEL@@
    text = text:gsub('@@LABEL@@', function()
        local invokeString = string.format(
            "{{#invoke:Bozza/GianAntonucci/Wikidata|getLabel|%s}}",
            wikidataId
        )
        
        local success, result = pcall(function()
            return frame:preprocess(invokeString)
        end)
        
        return success and result or ""
    end)
    
    return text
end

local junciRingu -- Na dichiara anticipata, pû chiamari prima mû difinemu

--------------------------------------------------------------------------------
-- 4) SPUSTAMENTU DÎ STILI DI MUDEḌḌU MISI MALU
--------------------------------------------------------------------------------

-- Sta funzioni sposta i tichetti <templatestyles> e i lijami ê catijurìi chi
-- s'attròvanu nta l'elimenti <tr> doppu a fini dâ tichetta </tr>, accussì
-- l'HTML arresta vàlitu
local function abbersaCeddi(html)
    if not html or html == "" then
        return html
    end

	-- Spustamu i catijurìi
    local function spostaCatijuriiFora(stringa)
        -- Prisirbamu a scrittura urigginali nta l'output
        return mw.ustring.gsub(
            stringa,
            -- Pigghiamu </tr> e i spazzi janchi
	        '(%</[Tt][Rr]%>%s*)' ..
	        -- Pigghiamu [[Catigurìa:...]], nta vari ortugrafìi
	        '(%[%[%s*(?:' .. -- '[['
	            '[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy]|' .. -- 'Category'
	            '[Cc][Aa][Tt][Ii][Gg][Uu][Rr][Ìì][Aa]|' .. -- 'Catigurìa'
	            '[Cc][Aa][Tt][Ii][Jj][Uu][Rr][Ìì][Aa]' ..  -- 'Catijurìa'
	        ')%s*:' .. -- ':'
	        '[^%]]*' .. -- Chiḍḍu c'arresta, nzinu â fini
	        '%]%] )',  -- ']]'
	        -- Scanciamu i dui pezzi chi pigghiammu
	        '%2%1'
        )
    end
    html = spostaCatijuriiFora(html)

    -- Spustamu i tichetti <templatestyles>
    html = mw.ustring.gsub(
        html,
        '(%</[Tt][Rr]%>%s*)(%f[%S]<templatestyles[^>]*>.-</templatestyles>)',
        '%2%1'
    )

    -- Spustamu 'UNIQ--templatestyles-....-QINU', alivoti MediaWiki u misi
    html = mw.ustring.gsub(
        html,
        '(%</[Tt][Rr]%>%s*)(\127[^\127]*UNIQ%-%-templatestyles%-%x+%-QINU[^\127]*\127)',
        '%2%1'
    )

    return html
end

--------------------------------------------------------------------------------
-- 5) FUNZIONI DI BASI PI JÙNCIRI UN RINGU
--------------------------------------------------------------------------------

-- Sta funzioni junci na riga â tèssira
-- 
-- A tabeḍḍa "paramitri" po aviri:
-- a) paramitri.gruppu => na stringa pû tìtulu d'un gruppu chi pigghia du' culonni
-- b) paramitri.vuci   => na stringa pâ tichetta dû ringu (facurtativu)
-- c) paramitri.valuri => na stringa pû valuri di ḍḍa tichetta
-- d) paramitri.classi => classi CSS di jùnciri â ceḍḍa dû valuri
junciRingu = function(radica, paramitri, statu)
    -- Siḍḍu è un tìtulu d'un gruppu, criamu un ringu pû tìtulu
    if paramitri.gruppu then
        radica:tag('tr')
            :addClass('tessira_gruppu')
            :tag('th')
                :attr('colspan', '2')
                :wikitext(paramitri.gruppu)
        return
    end

    -- Siḍḍu valuri nun cci nn'è, nun facemu nenti
    if not paramitri.valuri or paramitri.valuri == "" then
        return
    end

    -- Cuntrullamu siḍḍu u valuri àvi sulu rifirenzi e/o catijurìi
    if eVacantiLivannuRifirenziECatijurii(paramitri.valuri) then
        table.insert(statu.empty_row_extras, paramitri.valuri)
        return
    end

    -- Siḍḍu cc'è testu, criamu e facemu vìdiri un ringu
    statu.avi_ringhi = true
    local ringu = radica:tag('tr')

    if paramitri.vuci then
        -- Stampamu un ringu nurmali a du' culonni (tichetta + valuri)
        ringu:tag('th')
            :attr('scope', 'row')
            :addClass('tessira_vuci')
            :wikitext(paramitri.vuci)
            :done()
        local td = ringu:tag('td')
            :addClass('tessira_valuri')
        if paramitri.classi then
            td:addClass(paramitri.classi)
        end
        td:wikitext(cuntrollaLista(paramitri.valuri, paramitri.classi))
    else
        -- Siḍḍu tichetta nun cci nn'è, stampamu na ceḍḍa sula a du' culonni
        local td = ringu:tag('td')
            :attr('colspan', '2')
            :addClass('tessira_valuri')
        if paramitri.classi then
            td:addClass(paramitri.classi)
        end
        td:wikitext(cuntrollaLista(paramitri.valuri, paramitri.classi))
    end
end

--------------------------------------------------------------------------------
-- 9) NUMBERED ROWS + AUTOHEADERS
--------------------------------------------------------------------------------

-- This function looks for numbered rows like Vuci1/Valuri1, Vuci2/Valuri2, etc.
-- and processes them. These rows might also have:
-- a) Gruppu1, Gruppu2, etc. → Used to manually group rows into sections
-- b) Prupità1, Prupità2, etc. → Helps match data to Wikidata properties
-- c) Classi1, Classi2, etc. → CSS classes to apply to the valuri cell
local function renderNumberedRows(radica, args, statu)
    local wikidataId = args.Wikidata
    
    -- Load Wikidata entity if we have an ID and might need it
    local ntitaWikidata = nil
    if wikidataId and wikidataId ~= "" then
        local success, entity = pcall(mw.wikibase.getEntity, wikidataId)
        if success then
            ntitaWikidata = entity
        end
    end
    
    -- Step 1: Collect all indices that exist
    local indices = {}
    for key, value in pairs(args) do
        if type(key) == 'string' then
            -- Match any of our numbered parameters
            local index = key:match("^Vuci(%d+)$") or 
                          key:match("^Valuri(%d+)$") or
                          key:match("^Gruppu(%d+)$") or
                          key:match("^Prupità(%d+)$") or
                          key:match("^Classi(%d+)$")
            if index then
                indices[tonumber(index)] = true
            end
        end
    end
    
    -- Step 2: Sort indices
    local sortedIndices = {}
    for index in pairs(indices) do
        table.insert(sortedIndices, index)
    end
    table.sort(sortedIndices)
    
    -- Step 3: Process each index in order
    for _, index in ipairs(sortedIndices) do
        local vuciParam   = args["Vuci"   .. index]
        local valuriParam = args["Valuri" .. index]
        local gruppuParam = args["Gruppu" .. index]
        local propertyParam = args["Prupità" .. index]
        local classiParam = args["Classi" .. index]
        
        -- If Valuri is empty but Prupità is specified, fetch from Wikidata
        if (not valuriParam or valuriParam == "") and propertyParam and propertyParam ~= "" and ntitaWikidata then
            valuriParam = pigghiaValuriWikidata(ntitaWikidata, propertyParam)
        end
        
        -- Process if there's a valuri or group
        if (valuriParam and valuriParam ~= "") or (gruppuParam and gruppuParam ~= "") then
            -- Process Wikidata markers
            if valuriParam and wikidataId then
                valuriParam = processWikidataMarkers(valuriParam, wikidataId)
            end
            
            -- Add group header if specified
            if gruppuParam and gruppuParam ~= "" then
                junciRingu(radica, { gruppu = gruppuParam }, statu)
            end
            
            -- Add row if there's data to display
            if vuciParam or valuriParam then
                junciRingu(radica, { 
                    vuci = vuciParam, 
                    valuri = valuriParam, 
                    classi = classiParam 
                }, statu)
            end
        end
    end
end

--------------------------------------------------------------------------------
-- 10) ABOVE & BELOW ROWS
--------------------------------------------------------------------------------

-- This function optionally create a row spanning two columns at the top of
-- the table with that text, if the user sets "|Supra=Some text".
local function renderAbove(radica, args, statu)
    if args["Supra"] and mw.text.trim(args["Supra"]) ~= "" then
        statu.avi_ringhi = true
        local row = radica:tag('tr')
        row:tag('th')
            :attr('colspan', '2')
            :addClass('tessira_supra')
            :wikitext(args["Supra"])
    end
end

-- This function optionally creates a row spanning two columns at the bottom of
-- the table with that text, if the user sets "|Sutta=Some text".
local function renderBelow(radica, args, statu)
    if args["Sutta"] and mw.text.trim(args["Sutta"]) ~= "" then
        statu.avi_ringhi = true
        local row = radica:tag('tr')
        row:tag('td')
            :attr('colspan', '2')
            :addClass('tessira_sutta')
            :wikitext(args["Sutta"])
    end
end

--------------------------------------------------------------------------------
-- 11) SUBHEADER ROWS
--------------------------------------------------------------------------------

-- This function creates a subheader row spanning two columns that looks like
-- a small heading within the table.
local function renderSubheader(radica, subheaderText, statu)
    if subheaderText and subheaderText ~= "" then
        statu.avi_ringhi = true
        local row = radica:tag('tr')
        row:tag('td')
            :attr('colspan', '2')
            :addClass('tessira_subheader')
            :wikitext(subheaderText)
    end
end

-- This function loops through subheader1, subheader2, etc. until we don't find
-- subheaderN. Each one becomes a separate subheader row.
local function renderAllSubheaders(radica, args, statu)
    local i = 1
    while true do
        local key = "Abbirtenza" .. i
        local val = args[key]
        if not val or val == "" then
            break
        end
        renderSubheader(radica, val, statu)
        i = i + 1
    end
end

--------------------------------------------------------------------------------
-- 12) TITLE, IMAGES, NAVBAR, FOOTER
--------------------------------------------------------------------------------

-- This function renders the main title (Tìtulu) and an optional subtitle
-- (Suttatìtulu) spanning two columns at the top.
local function renderTitle(radica, args, statu)
    if args["Tìtulu"] and mw.text.trim(args["Tìtulu"]) ~= "" then
    	statu.avi_ringhi = true
        radica:tag('tr'):tag('th')
            :attr('colspan', '2')
            :addClass('tessira_titulu')
            :wikitext(args["Tìtulu"])
    end
    if args["Suttatìtulu"] and mw.text.trim(args["Suttatìtulu"]) ~= "" then
    	statu.avi_ringhi = true
        radica:tag('tr'):tag('th')
            :attr('colspan', '2')
            :addClass('tessira_suttatitulu')
            :wikitext(args["Suttatìtulu"])
    end
end

-- This function handles up to four images (top, bottom, left, right), plus
-- optional captions. Also attempts to fetch a top image from Wikidata (P18) if
-- the local parameter "MmàgginiSupra" isn't set.
local function renderImages(radica, args, statu, ntitaWikidata)
    local images = {
        top    = args["MmàgginiSupra"] or pigghiaValuriWikidata(ntitaWikidata, "P18"),
        bottom = args["MmàgginiSutta"],
        left   = args["MmàgginiManuManca"],
        right  = args["MmàgginiManuDritta"]
    }

    -- TOP IMAGE
    if images.top and images.top ~= "" then
    	statu.avi_ringhi = true
        radica:tag('tr'):tag('td')
            :attr('colspan', '2')
            :addClass('tessira_mmaggini')
            :wikitext('[[File:' .. images.top .. '|frameless|center]]')
    end
    if args["DidascalìaMmàgginiSupra"] and args["DidascalìaMmàgginiSupra"] ~= "" then
    	statu.avi_ringhi = true
        radica:tag('tr'):tag('td')
            :attr('colspan', '2')
            :addClass('tessira_didascalia_mmaggini')
            :wikitext(args["DidascalìaMmàgginiSupra"])
    end

    -- LEFT / RIGHT IMAGES
    if (images.left and images.left ~= "") or (images.right and images.right ~= "") then
    	statu.avi_ringhi = true
        local row = radica:tag('tr')
        row:tag('td')
            :addClass('tessira_mmaggini_manu_manca')
            :wikitext(images.left and images.left ~= "" and ('[[File:' .. images.left .. '|frameless|left]]') or "")
        row:tag('td')
            :addClass('tessira_mmaggini_manu_dritta')
            :wikitext(images.right and images.right ~= "" and ('[[File:' .. images.right .. '|frameless|right]]') or "")
    end
    if (args["DidascalìaMmàgginiManuManca"] and args["DidascalìaMmàgginiManuManca"] ~= "") or 
       (args["DidascalìaMmàgginiManuDritta"] and args["DidascalìaMmàgginiManuDritta"] ~= "") then
       	statu.avi_ringhi = true
        local row = radica:tag('tr')
        row:tag('td')
            :addClass('tessira_didascalia_mmaggini_manu_manca')
            :wikitext(args["DidascalìaMmàgginiManuManca"] or "")
        row:tag('td')
            :addClass('tessira_didascalia_mmaggini_manu_dritta')
            :wikitext(args["DidascalìaMmàgginiManuDritta"] or "")
    end

    -- BOTTOM IMAGE
    -- if images.bottom and images.bottom ~= "" then
    -- 	statu.avi_ringhi = true
    --     radica:tag('tr'):tag('td')
    --         :attr('colspan', '2')
    --         :addClass('tessira_mmaggini')
    --         :wikitext('[[File:' .. images.bottom .. '|frameless|center]]')
    -- end
    -- BOTTOM IMAGE (with fix)
	if images.bottom and images.bottom ~= "" then
	    statu.avi_ringhi = true
	    local td = radica:tag('tr'):tag('td')
	        :attr('colspan', '2')
	        :addClass('tessira_mmaggini')
	
	    -- Check if the content is already a complex HTML block
	    if mw.ustring.sub(mw.text.trim(images.bottom), 1, 4) == '<div' then
	        -- If it starts with a <div>, it's already HTML. Output it directly.
	        td:wikitext(images.bottom)
	    else
	        -- Otherwise, it's a simple filename. Wrap it in [[File:...]] as before.
	        td:wikitext('[[File:' .. images.bottom .. '|frameless|center]]')
	    end
	end
    if args["DidascalìaMmàgginiSutta"] and args["DidascalìaMmàgginiSutta"] ~= "" then
    	statu.avi_ringhi = true
        radica:tag('tr'):tag('td')
            :attr('colspan', '2')
            :addClass('tessira_didascalia_mmaggini')
            :wikitext(args["DidascalìaMmàgginiSutta"])
    end
end

-- This function optionally calls {{Lijami sinòtticu}} to show a navigation bar
-- at the bottom. If "LijamiWikidata" is not set to "Se", we pass "nowd=1" to 
-- hide the Wikidata link.
local function renderNavBar(radica, args, statu)
    if args["NomuMudeḍḍu"] then
        -- Clear and explicit navbar argument handling
        local navArgs
        if args["LijamiWikidata"] and string.lower(args["LijamiWikidata"]) == "se" then
            navArgs = { args["NomuMudeḍḍu"] }
        else
            navArgs = { args["NomuMudeḍḍu"], nowd = 1 } -- Junci "no wikidata"
        end
        
        radica:tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :addClass('tessira_navbar noprint nomobile metadata')
                :wikitext(mw.getCurrentFrame():expandTemplate{
                    title = 'Lijami sinòtticu',
                    args = navArgs
                })
    end
end

-- This function optionally adds a final row that can show disclaimers or sources.
local function renderFooter(radica, args, statu)
    if args["PediPàggina"] and mw.text.trim(args["PediPàggina"]) ~= "" then
        radica:tag('tr'):tag('td')
            :attr('colspan', '2')
            :addClass('tessira_pedi_paggina')
            :wikitext(args["PediPàggina"])
    end
end

--------------------------------------------------------------------------------
-- 13) BUILD TABLE
--------------------------------------------------------------------------------

-- This function builds either a <table> (default) or a <div> (èFigghia="Se"), then
-- calls each section-rendering function in a turn. If no rows are added,
-- avi_ringhi remains false, so we return nothing and don't display anything.
local function buildInfobox(args, ntitaWikidata)
    -- Create local statu
    local statu = {
        avi_ringhi = false,
        empty_row_extras = {}
    }

    local container
    if args["èFigghia"] and string.lower(args["èFigghia"]) == "se" then
        container = mw.html.create('div'):addClass('tessira_child_wrapper')
    else
        container = mw.html.create('table'):addClass('tessira')
        
        if args["SenzaCurrenti"] and string.lower(args["SenzaCurrenti"]) == "se" then
            container:addClass('tessira_no_float')
        end
    end

    if args["StiliARingu"] then
        container:attr('style', tostring(args["StiliARingu"]))
    end
    
    -- Pass statu to all render functions
    renderAbove(container, args, statu)
    renderTitle(container, args, statu)
    renderAllSubheaders(container, args, statu)
    renderImages(container, args, statu, ntitaWikidata)
    renderNumberedRows(container, args, statu)
    renderNavBar(container, args, statu)
    renderBelow(container, args, statu)
    renderFooter(container, args, statu)

    -- Return both container and statu
    return container, statu
end

--------------------------------------------------------------------------------
-- 14) DETECT HL/PL CLASSES (HLIST & PLAINLIST)
--------------------------------------------------------------------------------

-- Our module scans the arguments to see if "hlist" or "plainlist" is used somewhere.
-- If found, we automatically load the corresponding CSS using <templatestyles>.
local lists = {
    plainlist_t = {
        patterns = {
            '^plainlist$',
            '%splainlist$',
            '^plainlist%s',
            '%splainlist%s'
        },
        found = false,
        styles = PIRCURSU_CSS_LISTA_SIMPLICI
    },
    hlist_t = {
        patterns = {
            '^hlist$',
            '%shlist$',
            '^hlist%s',
            '%shlist%s'
        },
        found = false,
        styles = PIRCURSU_CSS_LISTA_URIZZUNTALI
    }
}

-- This function scans all parameters for "hlist" or "plainlist". If found, we
-- mark that style as "found", so we can load its CSS later.
local function has_list_class(args_to_check)
    for _, list in pairs(lists) do
        if not list.found then
            for key, arg in pairs(args_to_check) do
            	if type(key) == 'string' then -- Check that the key is text
	                -- Check both the valuri and if it's a Classi parameter
	                if key:match("^Classi%d*$") and arg then
	                    if arg:find(list.patterns[1]:gsub("^%^", ""):gsub("%$$", "")) then
	                        list.found = true
	                        break
	                    end
	                end
	                -- Original pattern checking
	                for _, pattern in ipairs(list.patterns) do
	                    if mw.ustring.find(arg or '', pattern) then
	                        list.found = true
	                        break
	                    end
	                end
	            end
                if list.found then break end
            end
        end
    end
end

--------------------------------------------------------------------------------
-- 15) MAIN FUNCTION
--------------------------------------------------------------------------------

-- This function is the main entry point. Usually called with
-- {{#invoke:ModuleName|stampa}} in wiki markup.
function p.stampa(frame)
    local args = {}
    local parentArgs = frame:getParent().args
    local localArgs = frame.args

    -- Merge arguments (simplified)
    for k, v in pairs(localArgs) do
        args[k] = v
    end
    for k, v in pairs(parentArgs) do
        args[k] = args[k] or v
    end

    -- Check for "hlist" or "plainlist"
    has_list_class(args)

    -- Load Wikidata entity with error handling
    local ntitaWikidata
    local wikidataSuccess = true
    
    -- Check if Wikidata parameter exists AND is not empty
    if args["Wikidata"] and args["Wikidata"] ~= "" then
        wikidataSuccess, ntitaWikidata = pcall(mw.wikibase.getEntity, args["Wikidata"])
    elseif not args["Wikidata"] then
        -- Only try to get current page entity if Wikidata param is not set at all
        wikidataSuccess, ntitaWikidata = pcall(mw.wikibase.getEntity)
    else
        -- Wikidata param is empty string, don't try to load entity
        wikidataSuccess = false
        ntitaWikidata = nil
    end
    
    if not wikidataSuccess then
        ntitaWikidata = nil
    end

    -- Build the table or <div> and get statu
    local container, statu = buildInfobox(args, ntitaWikidata)
    local html = tostring(container)

    -- Fix <templatestyles> or categories
    html = abbersaCeddi(html)

    -- Load any required CSS
    local css = ""

    -- Load default css
    if not args["Stili"] or args["Stili"]:lower() == "tessira" then
        css = css .. mw.getCurrentFrame():extensionTag{
            name = 'templatestyles',
            args = { src = PIRCURSU_CSS_PRIDIFINITU }
        }
    end

    -- Load styles for plainlist and hlist
    for _, list in pairs(lists) do
        if list.found then
            css = css .. mw.getCurrentFrame():extensionTag{
                name = 'templatestyles',
                args = { src = list.styles }
            }
        end
    end

    -- Build the final output
    local output = ""
    if statu.avi_ringhi then
        output = css .. html
    end

    -- Append categories/references from "empty" rows
    if #statu.empty_row_extras > 0 then
        output = output .. "\n<!-- References/categories from empty rows: -->\n"
        for _, extra in ipairs(statu.empty_row_extras) do
            output = output .. extra .. "\n"
        end
    end

    -- Add debug info if requested
	if args["Arrivisiona"] and string.lower(args["Arrivisiona"]) == "se" then
	    local debug_info = {}
	    for k, v in pairs(args) do
	        if not eParamitruCanusciutu(k) then
	            table.insert(debug_info, k)
	        end
	    end
	    if #debug_info > 0 then
	        -- HTML comment version (for viewing in source)
	        output = output .. "\n<!-- Paràmitri scanusciuti: " .. table.concat(debug_info, ", ") .. " -->\n"
	        
	        -- Visible warning box (for testing/debugging)
	        output = output .. '<div style="background:yellow;border:2px solid red;padding:10px;">Accura! Certi paràmitri nun si pòttiru arricanùsciri: ' .. table.concat(debug_info, ", ") .. '</div>'
	    end
	end

    return output
end

return p