Aller au contenu

Module:ArgumentContent

De Wikidébats, l'encyclopédie des débats et des arguments « pour » et « contre »

La documentation pour ce module peut être créée à Module:ArgumentContent/doc

local p = {}

--	========================
--	I18N
--	========================
local MESSAGES = {
	fr = {
		--	Libellés d'UI
		justifs_title = "Justifications",
		objs_title = "Objections",
		edit = "modifier",
		edit_justifs_tt = "Modifier la liste des arguments ci-dessous",
		edit_objs_tt = "Modifier la liste des objections ci-dessous",
		add_argument = "Ajouter un argument",
		add_objection = "Ajouter une objection",
		add_justif_tt = "Ajouter une justification à l'argument : %s",
		add_obj_tt = "Ajouter une objection à l'argument : %s",
		none_argument = "''Aucun argument n'a été entré.''",
		none_objection = "''Aucune objection n'a été entrée.''",
		none_content = "''Aucun contenu n'a été entré.''",
		detailed_debate_title = "%s",

		--	Termes structurants
		prop_page_params = "Paramètres de la page",
		prop_argument_content = "Contenu d'argument",
		prop_arguments_map = "Carte des arguments",

		form_justifications = "Justifications",
		form_objections = "Objections",
		form_new_argument_title = "Nouveau titre d'argument",
		form_type = "type",

		type_justification = "Justification",
		type_objection = "Objection",

		--	Modèles
		template_banner = "Bandeau %s",
	},
	en = {
		--	UI labels
		justifs_title = "Supporting arguments",
		objs_title = "Objections",
		edit = "edit",
		edit_justifs_tt = "Edit the list of arguments below",
		edit_objs_tt = "Edit the list of objections below",
		add_argument = "Add an argument",
		add_objection = "Add an objection",
		add_justif_tt = "Add a supporting argument to: %s",
		add_obj_tt = "Add an objection to: %s",
		none_argument = "''No argument has been entered.''",
		none_objection = "''No objection has been entered.''",
		none_content = "''No content has been entered.''",
		detailed_debate_title = "%s",

		prop_page_params = "Page parameters",
		prop_argument_content = "Argument content",
		prop_arguments_map = "Arguments map",

		form_justifications = "Supporting arguments",
		form_objections = "Objections",
		form_new_argument_title = "New argument title",
		form_type = "type",

		type_justification = "Justification",
		type_objection = "Objection",

		template_banner = "%s banner",
	},
	es = {
		justifs_title = "Justificaciones",
		objs_title = "Objeciones",
		edit = "editar",
		edit_justifs_tt = "Editar la lista de argumentos de abajo",
		edit_objs_tt = "Editar la lista de objeciones de abajo",
		add_argument = "Añadir un argumento",
		add_objection = "Añadir una objeción",
		add_justif_tt = "Añadir una justificación a: %s",
		add_obj_tt = "Añadir una objeción a: %s",
		none_argument = "''No se ha introducido ningún argumento.''",
		none_objection = "''No se ha introducido ninguna objeción.''",
		none_content = "''No se ha introducido ningún contenido.''",
		detailed_debate_title = "%s",

		prop_page_params = "Parámetros de la página",
		prop_argument_content = "Contenido del argumento",
		prop_arguments_map = "Mapa de argumentos",

		form_justifications = "Justificaciones",
		form_objections = "Objeciones",
		form_new_argument_title = "Nuevo título de argumento",
		form_type = "tipo",

		type_justification = "Justificación",
		type_objection = "Objeción",

		template_banner = "Aviso %s",
	},
}

--	========================
--	Helpers
--	========================
local function trim(s)
	if type(s) ~= "string" then
		return s
	end
	return s:match("^%s*(.-)%s*$")
end

local function split(s, delim)
	if type(s) ~= "string" or s == "" then
		return {}
	end
	if not delim or delim == "" then
		return { s }
	end
	delim = delim or ","
	local out = {}
	local esc = delim:gsub("(%W)", "%%%1")
	for part in (s .. delim):gmatch("(.-)" .. esc) do
		table.insert(out, trim(part))
	end
	return out
end

local function safeIndex(t, idx, default)
	if type(t) ~= "table" then
		return default
	end
	local v = t[idx]
	if v == nil or v == "" then
		return default
	end
	return v
end

local function toNumber(s, default)
	local n = tonumber(s or "")
	return n or default or 0
end

local function urlencode(s, mode)
	return mw.uri.encode(s or "", mode or "QUERY")
end

local function anchorencode(s)
	return mw.uri.anchorEncode(s or "")
end

--	========================
--	I18N helpers
--	========================
local function normalizeLang(code)
	code = trim(code or "")
	if code == "" then
		return ""
	end
	local base = code:match("^([a-zA-Z]+)") or code
	return mw.ustring.lower(base)
end

local function getLang(args)
	local param = normalizeLang(args.lang or args.language or "")
	if param ~= "" and MESSAGES[param] then
		return param
	end
	local contentLang = ""
	if mw.getContentLanguage then
		local obj = mw.getContentLanguage()
		if obj and obj.getCode then
			contentLang = normalizeLang(obj:getCode())
		end
	end
	if contentLang ~= "" and MESSAGES[contentLang] then
		return contentLang
	end
	return "en"
end

local function msg(lang, key, ...)
	local pack = MESSAGES[lang] or MESSAGES.en
	local text = pack[key] or (MESSAGES.en and MESSAGES.en[key]) or key
	if select("#", ...) > 0 then
		return string.format(text, ...)
	end
	return text
end

--	========================
--	SMW access
--	========================
local function smwShow(frame, page, property)
	if not page or page == "" or not property or property == "" then
		return ""
	end
	if mw.smw and type(mw.smw.getQueryResult) == "function" then
		local res = mw.smw.getQueryResult{
			conditions = { string.format("[[%s]]", page) },
			printouts = { property },
			parameters = { mainlabel = "-" }
		}
		if not res or not res.results or not res.results[1] then
			return ""
		end
		local first = res.results[1]
		for _, po in ipairs(first.printouts or {}) do
			if po.label == property then
				local vals = {}
				for _, v in ipairs(po.values or {}) do
					table.insert(vals, tostring(v.value or v))
				end
				return table.concat(vals, ", ")
			end
		end
		return ""
	else
		local txt = frame:callParserFunction("#show", { page, "?" .. property })
		return trim(txt or "")
	end
end

local function smwAskOneTitle(frame, condition)
	if not condition or condition == "" then
		return ""
	end
	if mw.smw and type(mw.smw.getQueryResult) == "function" then
		local res = mw.smw.getQueryResult{
			conditions = { string.format("[[%s]]", condition) },
			printouts = {},
			parameters = { mainlabel = "page", limit = 1 }
		}
		if not res or not res.results or not res.results[1] then
			return ""
		end
		return res.results[1].fulltext or ""
	else
		local txt = frame:callParserFunction("#ask", {
			string.format("[[%s]]", condition),
			"link=none",
			"limit=1",
		})
		return trim(txt or "")
	end
end

--	========================
--	Page Forms helpers
--	========================
local function formlink(frame, form, target, linktext, tooltip)
	return frame:callParserFunction("#formlink", {
		"form=" .. (form or ""),
		"target=" .. (target or ""),
		"link text=" .. (linktext or ""),
		"tooltip=" .. (tooltip or "")
	})
end

local function queryformlink(frame, form, querystring, linktype, linktext, tooltip)
	return frame:callParserFunction("#queryformlink", {
		"form=" .. (form or ""),
		"query string=" .. (querystring or ""),
		"link type=" .. (linktype or ""),
		"link text=" .. (linktext or ""),
		"tooltip=" .. (tooltip or "")
	})
end

--	========================
--	Bandeaux
--	========================
local function expandBandeaux(frame, csv, lang)
	if not csv or csv == "" then
		return ""
	end
	local html = {}
	for _, item in ipairs(split(csv, ",")) do
		if item and item ~= "" then
			local title = msg(lang, "template_banner", item)
			table.insert(html, frame:expandTemplate{
				title = title,
				args = { item }
			})
		end
	end
	return table.concat(html, " ")
end

--	========================
--	Rendu principal
--	========================
function p.render(frame)
	local args = frame:getParent() and frame:getParent().args or frame.args
	local L = getLang(args)

	local pageArgument = mw.uri.decode(trim(args.argument or ""))
	local cheminRaw = trim(args.path or args.chemin or "")
	local niveau = toNumber(args.level or args.niveau, 0) + 1
	local typeArg = trim(args.type or "")
	local avertissements = trim(args.warnings or args.avertissements or "")
	local pageParam = trim(args.page or "")

	local cheminParts = split(cheminRaw, "@@@")
	local lastPath = safeIndex(cheminParts, #cheminParts, "")
	local racineParts = split(lastPath, ":::")
	local racine = safeIndex(racineParts, 2, "")

	local pageDestination = smwAskOneTitle(frame, pageArgument)

	local paramsRaw = smwShow(frame, pageArgument, msg(L, "prop_page_params"))
	if paramsRaw == "" and L ~= "fr" then
		paramsRaw = smwShow(frame, pageArgument, MESSAGES.fr.prop_page_params)
	end
	local params = split(paramsRaw, "<>")

	if not params[1] or params[1] == "" then
		return '<div class="aucun-contenu">' .. msg(L, "none_content") .. '</div>__NOTOC__'
	end

	local idArgument				= safeIndex(params, 1, "")
	local pairesJustifsRaw			= safeIndex(params, 2, "")
	local pairesObjRaw				= safeIndex(params, 3, "")
	local nbJustifs					= toNumber(safeIndex(params, 4, "0"), 0)
	local nbObjs					= toNumber(safeIndex(params, 5, "0"), 0)
	local pageDebatDetaille			= safeIndex(params, 6, "")
	local bandeauxJustifsCsv		= safeIndex(params, 7, "")
	local bandeauxObjsCsv			= safeIndex(params, 8, "")

	local contenuArgument = smwShow(frame, pageArgument, msg(L, "prop_argument_content"))
	if (contenuArgument == "" or contenuArgument == nil) and L ~= "fr" then
		contenuArgument = smwShow(frame, pageArgument, MESSAGES.fr.prop_argument_content)
	end

	local avertHtml = ""
	if avertissements and avertissements ~= "" then
		avertHtml = expandBandeaux(frame, avertissements, L)
	end

	local preOpen, preClose = "", ""
	if niveau == 1 then
		preOpen = string.format('<div class="contenu-argument-%s">', typeArg or "")
		preClose = '</div>'
	end

	local bodyHtml = {}

	table.insert(bodyHtml, string.format(
		'<div class="contenu-argument">%s</div>',
		contenuArgument or ""
	))

	if pageDebatDetaille and pageDebatDetaille ~= "" then
		local carteProp = msg(L, "prop_arguments_map")
		local carteArgs = smwShow(frame, pageDebatDetaille, carteProp)
		if (carteArgs == "" or carteArgs == nil) and L ~= "fr" then
			carteArgs = smwShow(frame, pageDebatDetaille, MESSAGES.fr.prop_arguments_map)
		end
		table.insert(bodyHtml, string.format([===[
	<div class="carte-debat-detaille onglet-externe">
		<div class="titre-debat-detaille">%s</div>
		%s
	</div>]===], msg(L, "detailed_debate_title", pageDebatDetaille), carteArgs or ""))
	else
		local function buildList(pairesRaw, count, sens, sensInverseOpt)
			local out = {}
			local paires = split(pairesRaw, "&&&")
			local sensInverse = sensInverseOpt
			for i = 1, count do
				local paire = split(safeIndex(paires, i, ""), "-¡-")
				local id = safeIndex(paire, 1, "")
				local titre = safeIndex(paire, 2, id)
				local titreEnc = urlencode(titre)
				local idEnc = urlencode(id)

				local t = sens
				if sensInverse then
					t = (typeArg == "pour") and "contre" or "pour"
				end

				table.insert(out, string.format([===[
	<div class="argument-expandable">
		<div id="%s" class="argument argument-expandable-title level-%d level-sup"
			data-template="%s"
			data-page="%s"
			data-argument="%s"
			data-type="%s"
			data-level="%d"
			data-root="%s"
			data-path="%s@@@%s:::%s"
			data-warnings="%s"
			>[[File: Expand.svg | 13px | link= | alt= | class=fleche-deroulante]][[File: Argument-%s.svg | 17px | link= | alt= | class=pictogramme-h4 mw-no-invert]]<span>%s</span>
		</div>
		<div class="argument-content-wrapper"></div>
	</div>]===],
					anchorencode(titre),
					niveau,
					msg(L, "prop_argument_content"),
					mw.text.nowiki(pageParam or ""),
					idEnc,
					mw.text.nowiki(t),
					niveau,
					mw.text.nowiki(racine),
					mw.text.nowiki(cheminRaw or ""),
					mw.text.nowiki(t),
					titreEnc,
					mw.text.nowiki(avertissements or ""),
					mw.text.nowiki(t),
					mw.text.nowiki(titre)
				))
			end
			if #out == 0 then
				if sensInverse then
					return '<div class="aucun-argument">' .. msg(L, "none_objection") .. "</div>"
				else
					return '<div class="aucun-argument">' .. msg(L, "none_argument") .. "</div>"
				end
			end
			return table.concat(out, "")
		end

		local formJust = msg(L, "form_justifications")
		local formObj = msg(L, "form_objections")
		local formNew = msg(L, "form_new_argument_title")
		local formType = msg(L, "form_type")

		if L ~= "fr" then
			formJust = formJust ~= "" and formJust or MESSAGES.fr.form_justifications
			formObj = formObj ~= "" and formObj or MESSAGES.fr.form_objections
			formNew = formNew ~= "" and formNew or MESSAGES.fr.form_new_argument_title
			formType = formType ~= "" and formType or MESSAGES.fr.form_type
		end

		local modJust = formlink(
			frame,
			formJust,
			pageDestination,
			msg(L, "edit"),
			msg(L, "edit_justifs_tt")
		)
		local modObj = formlink(
			frame,
			formObj,
			pageDestination,
			msg(L, "edit"),
			msg(L, "edit_objs_tt")
		)

		local typeJust = msg(L, "type_justification")
		local typeObj = msg(L, "type_objection")
		if L ~= "fr" then
			typeJust = typeJust ~= "" and typeJust or MESSAGES.fr.type_justification
			typeObj = typeObj ~= "" and typeObj or MESSAGES.fr.type_objection
		end

		local btnJust = queryformlink(
			frame,
			formNew,
			string.format("%s[%s]=%s&%s[ID]=%s&_run",
				formNew,
				formType,
				(typeJust or ""),
				formNew,
				(idArgument or "")
			),
			"post button",
			msg(L, "add_argument"),
			msg(L, "add_justif_tt", (pageArgument or ""))
		)
		local btnObj = queryformlink(
			frame,
			formNew,
			string.format("%s[%s]=%s&%s[ID]=%s&_run",
				formNew,
				formType,
				(typeObj or ""),
				formNew,
				(idArgument or "")
			),
			"post button",
			msg(L, "add_objection"),
			msg(L, "add_obj_tt", (pageArgument or ""))
		)

		local gauche = string.format([===[
	<div class="colonne-gauche">
		<div class="NavFramex %s">
			<div class="NavHead"><span class="titre-boite">%s</span>
				<span class="modifier-section">%s</span></div>
			<div class="NavContent">
				<div>%s</div>
				%s
			</div>
			<div class="NavButton">
				<div class="bouton-ajouter navigation-not-searchable">%s</div>
			</div>
		</div>
	</div>]===],
			(typeArg == "pour") and "bordure-argument-pour" or "bordure-argument-contre",
			msg(L, "justifs_title"),
			modJust,
			expandBandeaux(frame, bandeauxJustifsCsv, L),
			(pairesJustifsRaw ~= "" and buildList(pairesJustifsRaw, nbJustifs, typeArg, false) or '<div class = "aucun-argument">' .. msg(L, "none_argument") .. "</div>"),
			btnJust
		)

		local droite = string.format([===[
	<div class="colonne-droite">
		<div class="NavFramex %s">
			<div class="NavHead"><span class="titre-boite">%s</span>
				<span class="modifier-section">%s</span></div>
			<div class="NavContent">
				<div>%s</div>
				%s
			</div>
			<div class="NavButton">
				<div class="bouton-ajouter navigation-not-searchable">%s</div>
			</div>
		</div>
	</div>]===],
			(typeArg == "pour") and "bordure-argument-contre" or "bordure-argument-pour",
			msg(L, "objs_title"),
			modObj,
			expandBandeaux(frame, bandeauxObjsCsv, L),
			(pairesObjRaw ~= "" and buildList(pairesObjRaw, nbObjs, typeArg, true) or '<div class="aucun-argument">' .. msg(L, "none_objection") .. "</div>"),
			btnObj
		)

		table.insert(bodyHtml, '<div class="colonnes">')
		table.insert(bodyHtml, gauche)
		table.insert(bodyHtml, droite)
		table.insert(bodyHtml, '</div>')
	end

	local html = {}
	if avertHtml ~= "" then
		table.insert(html, string.format('<div>%s</div>', avertHtml))
	end
	table.insert(html, preOpen)
	table.insert(html, table.concat(bodyHtml, ""))
	table.insert(html, preClose)
	table.insert(html, "__NOTOC__")

	return table.concat(html, "")
end

return p