La documentazione per questo modulo può essere creata in Modulo:Listing/sandbox/man

--[[
	Source script:	https://it.wikivoyage.org/wiki/Modulo:Listing
	Maintainer:		Andyrom75

	Lazy loads:
	require('Modulo:IsLatin').IsLatinValue
	require('Modulo:EmailTracking').EmailTrackingValue
	require('Modulo:Wikibase').label
	require('Modulo:WikidataIB').getSiteLink
]]
local Marker = require('Modulo:Marker/sandbox').MarkerModule
local LinkModule = require('Modulo:LinkPhone')


local function _templateStyle( frame, src )
   return frame:extensionTag( 'templatestyles', '', { src = src } )
end

local function _isDefined(s)
	return s ~= '' and s
end

function _hiddenUnicode( value )
    -- Note the quote ("") below is not empty and actually contains a hidden unicode character.
    return mw.ustring.match(value or '',"‎") and '[[Categoria:Listing con caratteri unicode nascosti]]<span class="unicodeinfo debuginfo" style="display:none;">UNICODE</span>' or ''
end

function _phone( phone )
    return '<abbr title="telefono" style="text-decoration:none">☎</abbr> <span class="tel listing-phone">'.. LinkModule.LinkPhone{ args={phone} } .. '</span>'
end

function _email( mail )
    return '<span class="email listing-email">' .. LinkModule.LinkEmail{ args={mail} } .. '</span>' .. require('Modulo:EmailTracking').EmailTrackingValue(mail)
end

function _concatIndexed( tab )
    local tt = {}
    for _, v in pairs( tab ) do
        tt[#tt+1] = v
    end
    return table.concat( tt )
end

function _validateParams( params )
	local validParams = {
		counter = true,
		tipo = true,
		nome = true,
		alt = true,
		sito = true,
		email = true,
		indirizzo = true,
		lat = true,
		long = true,
		indicazioni = true,
		tel = true,
		['numero verde'] = true,
		fax = true,
		orari = true,
		checkin = true,
		checkout = true,
		prezzo = true,
		descrizione = true,
		wikipedia = true,
		immagine = true,
		wikidata = true
	}
	local invalidParams = ''
	for key, _ in pairs( params ) do
		if not validParams[key] then
			invalidParams = invalidParams .. '<b>' .. key ..'</b>; '
		end
	end
	return _isDefined(invalidParams) and ('[[Categoria:Listing con errori di compilazione]]<span class="debuginfo" style="display:none;">Sono presenti parametri non gestiti: '.. invalidParams .. '</span>') or ''
end

local function _Listing(frame)
	local args = frame.args
	local output = '<bdi class="vcard">'
	--Marker creation
	local MarkerArgs = {
		counter = args.counter or args.tipo or 'listing',
		tipo = args.tipo or 'listing',
		nome = args.nome,
		lat = args.lat,
		long = args.long,
		immagine = args.immagine,
		sito = args.sito,
		islisting = 'yes',
		wikidata = args.wikidata
	}
	output = output .. Marker{ args = MarkerArgs }

	--Alt
	if _isDefined( args.alt ) then
		output = output .. '&#32;(<span class="nickname listing-alt ' .. (require('Modulo:IsLatin').IsLatinValue(args.alt) == 'sì' and 'IsLatin' or '') .. '">' .. args.alt .. '</span>)'
	end

	--Indirizzo
	local anyPrevData = args.nome or args.sito
	if _isDefined( args.indirizzo ) then
		output = output .. (anyPrevData and ',' or '') .. '&#32;<span class="adr listing-address street-address">' .. args.indirizzo .. '</span>'
		anyPrevData = true
	end

	--indicazioni
	if _isDefined( args.indicazioni ) then
		output = output .. '&#32;(<span class="adr listing-directions">' .. args.indicazioni .. ')</span>'
		anyPrevData = true
	end

	--Telefono
	if _isDefined( args.tel ) then
		output = output .. (anyPrevData and ',&#32;' or '&#32;') .. _phone(args.tel)
		anyPrevData = true
	end

	--Numero Verde
	if _isDefined( args['numero verde'] ) then
		output = output .. (anyPrevData and ',' or '')
			.. '&#32;<abbr title="numero verde" class="green">☎</abbr> <span class="tel listing-tollfree">'
			.. LinkModule.LinkPhone{ args={args['numero verde'], tollfree='yes'} }
			.. '</span>'
		anyPrevData = true
	end

	--Fax
	if _isDefined( args.fax ) then
		output = output .. (anyPrevData and ',' or '')
			.. '&#32;<span class="tel"><span class="type">fax</span>: <span class="value listing-fax">'
			.. LinkModule.LinkPhone{ args={args.fax, fax='true'} }
			.. '</span></span>'
		anyPrevData = true
	end

	--E-mail
	if _isDefined( args.email ) then
		output = output .. (anyPrevData and ',&#32;' or '&#32;') .. _email(args.email)
	end

	--Se sono state inserite informazioni nei campi precedenti, forzo un punto di fine periodo
	output = output .. (anyPrevData and '.' or '')

	--Prezzo
	if _isDefined( args.prezzo ) then
		output = output .. '&#32;<abbr title="prezzo">[[File:Ecb copyright.svg|13px|link=]]</abbr> <span class="note listing-price">'
			.. args.prezzo .. '</span>.'
	end

	--Orari
	if _isDefined( args.orari ) then
		output = output .. '&#32;<abbr title="orari">[[File:Simple icon time.svg|15px|link=]]</abbr> <span class="note listing-hours">'
			.. args.orari .. '</span>.'
	end

	--Check-in e checkout
	if _isDefined( args.checkin ) then
		output = output .. '&#32;<span class="note">Check-in: <span class="listing-checkin">' .. args.checkin .. '</span>'
		if _isDefined( args.checkout ) then
			output = output .. ', check-out: <span class="listing-checkout">' .. args.checkout .. '</span>'
		end
		output = output .. '</span>.'
	else
		if _isDefined( args.checkout ) then
			output = output .. '&#32;<span class="note">Check-out: <span class="listing-checkout">' .. args.checkout .. '</span></span>.'
		end
	end

	--Descrizione generale del listing in oggetto
	args.descrizione = _isDefined( args.descrizione ) or _isDefined( args[1] )
	if args.descrizione then
		--Sostituisco temporaneamente gli stili dei template utilizzati all'interno delle descrizioni per il loro contenuto può compromettere la succeessiva elaborazione
		local styles = {}
		local style = ''
		local patterns = {'(style=".-")', "(style='.-')"}
		for i=1, #patterns do
			local pos = mw.ustring.find(args.descrizione, patterns[i])
			while pos do
				style = mw.ustring.gsub(args.descrizione, '.-'..patterns[i]..'.*', '%1')
				styles[#styles+1] = style
				args.descrizione = mw.ustring.sub( args.descrizione, 1, pos-1 ) .. "<<§@§>>" .. mw.ustring.sub( args.descrizione, pos+#style)
				pos = mw.ustring.find(args.descrizione, patterns[i])
			end
		end

		local level1 = not mw.ustring.find(args.descrizione, '\n[\*#][\*#]') and not mw.ustring.find(args.descrizione, '\n:+[\*#:][\*#]')
		if mw.ustring.find(mw.ustring.sub(args.descrizione,1,1), '[:;\*#]') then
			-- se la descrizione inizia con un carattere speciale, lo mando a capo affiché venga correttamente gestito dal wiki-interprete
			args.descrizione = '\n' .. args.descrizione
		end
		
		-- limito le dispendiose gsub ai casi di descrizioni con righe-multiple
		-- inoltre, per le attuali limitazioni, evito di elaborare le descrizioni contenenti liste HTML a più livelli
		if mw.ustring.find(args.descrizione, '\n') and level1 then
			-- gestisco i casi più comuni di ";" sebbene ricreare l'esatto rendering del wiki-testo è praticamente impossibile
			if mw.ustring.find(args.descrizione, ';') then
				args.descrizione = mw.ustring.gsub(args.descrizione, "(\n:*);(:*[\*#])", "%1:%2")
				args.descrizione = mw.ustring.gsub(args.descrizione, "(\n):*;", "%1<<§>>")
				args.descrizione = mw.ustring.gsub(args.descrizione, "(\n:*([\*#][:;]*));", "%1<<§>>")
				args.descrizione = mw.ustring.gsub(args.descrizione, "<<§>>(.-)\n", "<dl><dt>%1</dt></dl>\n")
				args.descrizione = mw.ustring.gsub(args.descrizione, "<<§>>(.-)$", "<dl><dt>%1</dt></dl>")
			end
			local isUnorderedList = mw.ustring.find(args.descrizione, '\n:* *\*') or mw.ustring.find(args.descrizione, '^:* *\*')
			local isOrderedList = mw.ustring.find(args.descrizione, '\n:* *\#') or mw.ustring.find(args.descrizione, '^:* *\#')
			-- per attuali limitazioni elaboro solo descrizioni contenenti un unico tipo di liste
			if (isUnorderedList and not isOrderedList) or (isOrderedList and not isUnorderedList) then
				--contrassegno l'inizio di ogni item con un simbolo potenzialmente univoco
				args.descrizione = mw.ustring.gsub(args.descrizione, "\n:? *[\*#]", "\n<<§>>")
				args.descrizione = mw.ustring.gsub(args.descrizione, "<<§>>(.-)\n", "<li>%1</li>\n")
				args.descrizione = mw.ustring.gsub(args.descrizione, "<<§>>(.-)$", "<li>%1</li>")
				args.descrizione = mw.ustring.gsub(args.descrizione, "</li>\n*:*<li>", "</li><li>")
				if isUnorderedList then
					args.descrizione = mw.ustring.gsub(args.descrizione, "(<li>.-</li>\n)", "<ul>%1</ul>\n")
					args.descrizione = mw.ustring.gsub(args.descrizione, "(<li>.*</li>)$", "<ul>%1</ul>")
					args.descrizione = mw.ustring.gsub(args.descrizione, "</ul>\n:", "</ul>")
				elseif isOrderedList then
					args.descrizione = mw.ustring.gsub(args.descrizione, "(<li>.-</li>\n)", "<ol>%1</ol>\n")
					args.descrizione = mw.ustring.gsub(args.descrizione, "(<li>.*</li>)$", "<ol>%1</ol>")
					args.descrizione = mw.ustring.gsub(args.descrizione, "</ol>\n:", "</ol>")
				end
			end
			-- per attuali limitazioni evito di elaborare descrizioni contenenti sia liste ordinate che non ordinate
			if not (isUnorderedList and isOrderedList) then
				args.descrizione = mw.ustring.gsub(args.descrizione, "\n:+", "<br />")
				args.descrizione = mw.ustring.gsub(args.descrizione, "\n\n", "<br />")
				args.descrizione = mw.ustring.gsub(args.descrizione, "\n([^\n]+)", "%1")
			end
		end
		--ripristino gli stili rimossi
		for i=1, #styles do
			args.descrizione = mw.ustring.gsub(args.descrizione , '<<§@§>>', styles[i], 1)
		end
		output = output .. '&#32;<bdi class="note listing-content">' .. args.descrizione .. '</bdi>'
	end

	local metadata = ''
	--Sister project icons
	args.wikipedia = _isDefined( args.wikipedia )
	args.wikidata = _isDefined( args.wikidata )
	if args.wikipedia or args.wikidata then
		metadata = metadata .. '<span class="listing-sister-icons">'
		local wpLink = _isDefined( args.wikipedia )
		if args.wikidata then
			--in presenza dell'istanza wikidata, recupero i dati relativi alle versioni italiane di Wikivoyage e Wikipedia
			local WIB_wikivoyage = _isDefined( require('Modulo:WikidataIB').getSiteLink{args={wiki='itwikivoyage', qid=args.wikidata}} )
			if WIB_wikivoyage then
				metadata = metadata .. '&#32;[[File:Wikivoyage-logo.svg|15px|class=listing-sister|link=' .. WIB_wikivoyage .. '|<span>' .. WIB_wikivoyage .. '</span> quì su Wikivoyage]]'
			end
			wpLink = wpLink or _isDefined( require('Modulo:WikidataIB').getSiteLink{args={wiki='itwiki', qid=args.wikidata}} )
		end
		if args.wikipedia ~= 'NA' and wpLink then
			metadata = metadata .. '&#32;[[File:Wikipedia-icon.png|15px|class=listing-sister|link=w:' .. wpLink .. '|<span>' .. wpLink .. '</span> su Wikipedia]]'
		end
		if args.wikidata then
			metadata = metadata .. '&#32;[[File:Wikidata-logo.svg|16px|class=listing-sister|link=d:' .. args.wikidata
				..'|' .. (require('Modulo:Wikibase').label{args={args.wikidata}} or '') .. ' ('.. args.wikidata .. ') su Wikidata]]'
		end
		metadata = metadata .. '</span>'
	end

	--Metadata - last edit date, "edit" link, etc
	args.lastedit = _isDefined( args.lastedit )
	metadata = metadata .. '<span class="listing-metadata">'
	if args.lastedit then
		metadata = metadata .. '&nbsp;(<span class="listing-metadata-items"><span class="listing-lastedit">Aggiornamento: ' .. mw.getContentLanguage():formatDate( 'M Y', args.lastedit ) .. '</span></span>|)'
	else
		metadata = metadata .. '<span class="listing-metadata-items">&nbsp;</span>'
	end
	metadata = metadata .. '</span>'
--[[
	local match = 0
	output, match = mw.ustring.gsub( output, "(</..></[uod]l></bdi>)$", metadata .. "%1")
	if match == 0 then
		output = output .. metadata
	end
]]
	output, match = mw.ustring.gsub( output, "(</dt></dl></li></[uo]l></bdi>)$", metadata .. "%1")
	if match == 0 then
		output, match = mw.ustring.gsub( output, "(</..></[uod]l></bdi>)$", metadata .. "%1")
		if match == 0 then
			output = output .. metadata
		end
	end


	output = output .. '</bdi>'

	--Controllo la presenza di caratteri Unicode all'interno dei parametri forniti in input
	--A seguire controllo anche la presenza di parametri non gestiti da questo template
	output = output .. _hiddenUnicode( _concatIndexed( args ) ) .. _validateParams( args )
	if args.wikipedia and not args.wikidata then
			--Non è considerato un errore se il parametro Wikipedia è usato per puntare a una specifica sezione
			output = output .. (mw.ustring.find(args.wikipedia, '#') == 0 and '[[Categoria:Listing con link a Wikipedia ma non a Wikidata]]' or '')
	end

    return _templateStyle( frame, 'Listing/styles.css' ) .. output
end

local p = {}

function p.ListingTemplate(frame)
	return _Listing(frame:getParent())
end

function p.ListingInvoke(frame)
	return _Listing(frame)
end

function p.ListingModule(frame)
	local Cframe = mw.getCurrentFrame()
	Cframe.args = frame.args
	return _Listing(Cframe)
end

return p