Aller au contenu

Module:ArgumentMap

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:ArgumentMap/doc

--	Module:ArgumentMap (MediaWiki 1.43)
--	I18N : via Module:WD/I18N (DATA + @aliases + caches internes)
--	Perf :
--	-	mw.smw.ask (2 props en 1 requête)
--	-	Comparaison par page ID (renommage OK)
--	-	ask léger (mainlabel=-, headers=hide, link=none)
--	-	Cache split limité (listes courtes seulement)

local p = {}

----------------------------------------------------------------------
--	I18N (minimal) : délègue tout à Module:WD/I18N
----------------------------------------------------------------------

local WD_I18N	= require( 'Module:WD/I18N' )
local msg		= WD_I18N.msg

----------------------------------------------------------------------
--	Locaux (micro-opt)
----------------------------------------------------------------------

local mw					= mw
local smw					= mw.smw
local makeTitle				= mw.title.makeTitle
local title_new				= mw.title.new
local text_trim				= mw.text.trim
local uri_decode			= mw.uri.decode

local str_find				= string.find
local str_sub				= string.sub
local t_concat				= table.concat
local type					= type

----------------------------------------------------------------------
--	Constantes (perf)
----------------------------------------------------------------------

local SPLIT_CACHE_MAX		= 800

----------------------------------------------------------------------
--	Cache local (par parse)
----------------------------------------------------------------------

local _idCache				= {}	--	[titre] = id | false
local _listSplit			= {}	--	[delim.."\n"..listStr] = { ...paires... } (si #s <= SPLIT_CACHE_MAX)

----------------------------------------------------------------------
--	Helpers
----------------------------------------------------------------------

local function trim( s )
	return text_trim( s or "" )
end

local function urldecodeMaybe( s )
	s = trim( s )
	if s == "" then
		return ""
	end
	if not str_find( s, "%%", 1, true ) and not str_find( s, "+", 1, true ) then
		return s
	end
	return uri_decode( s )
end

local function titleFromText( titleText )
	if str_find( titleText, ":", 1, true ) then
		return title_new( titleText )
	end
	return makeTitle( 0, titleText )
end

local function idCached( titleText )
	titleText = trim( titleText )
	if titleText == "" then
		return nil
	end

	local cached = _idCache[ titleText ]
	if cached ~= nil then
		return ( cached ~= false ) and cached or nil
	end

	local t = titleFromText( titleText )
	if not t or not t.exists then
		_idCache[ titleText ] = false
		return nil
	end

	local id = t.id or nil
	_idCache[ titleText ] = id or false
	return id
end

local function splitListCached( s, delim )
	if s == "" then
		return {}
	end

	local useCache = ( #s <= SPLIT_CACHE_MAX )
	local key

	if useCache then
		key = delim .. "\n" .. s
		local cached = _listSplit[ key ]
		if cached then
			return cached
		end
	end

	local out = {}
	local start = 1
	local n = 0

	while true do
		local i, j = str_find( s, delim, start, true )
		if not i then
			n = n + 1
			out[ n ] = str_sub( s, start )
			break
		end
		n = n + 1
		out[ n ] = str_sub( s, start, i - 1 )
		start = j + 1
	end

	if useCache then
		_listSplit[ key ] = out
	end

	return out
end

local function splitPairOnce( s, delim )
	local i, j = str_find( s, delim, 1, true )
	if not i then
		return trim( s ), ""
	end
	return trim( str_sub( s, 1, i - 1 ) ), trim( str_sub( s, j + 1 ) )
end

local function renderTable( leftTitle, rightTitle, leftHtml, rightHtml )
	return t_concat{
		'<table style="background-color:transparent; width: 100%;" class="navigation-not-searchable">',
			'<tr>',
				'<th style="text-align:left;">', leftTitle, '</th>',
				'<th style="text-align:left; padding-left: 1em;">', rightTitle, '</th>',
			'</tr>',
			'<tr style="vertical-align:top;">',
				'<td><div class="is-pro">', leftHtml, '</div></td>',
				'<td style="padding-left: 1em;"><div class="is-con">', rightHtml, '</div></td>',
			'</tr>',
		'</table>'
	}
end

local function smwGetProps( subjectTitle, propNames )
	if not smw or not smw.ask then
		return {}
	end

	local ask = { '[[' .. subjectTitle .. ']]' }

	for i = 1, #propNames do
		if propNames[ i ] and propNames[ i ] ~= "" then
			ask[ #ask + 1 ] = '?' .. propNames[ i ]
		end
	end

	ask[ #ask + 1 ] = 'mainlabel=-'
	ask[ #ask + 1 ] = 'headers=hide'
	ask[ #ask + 1 ] = 'link=none'
	ask[ #ask + 1 ] = 'limit=1'

	local res = smw.ask( ask )
	if type( res ) ~= "table" or type( res[ 1 ] ) ~= "table" then
		return {}
	end

	local row = res[ 1 ]
	local out = {}

	for i = 1, #propNames do
		local k = propNames[ i ]
		if k and k ~= "" then
			local v = row[ k ]
			if type( v ) == "table" then
				out[ k ] = t_concat( v, "," )
			elseif type( v ) == "string" then
				out[ k ] = v
			else
				out[ k ] = ""
			end
		end
	end

	return out
end

local function smwGetProp( subjectTitle, propName )
	if not smw or not smw.ask or not propName or propName == "" then
		return ""
	end

	local ask = {
		'[[' .. subjectTitle .. ']]',
		'?' .. propName,
		'mainlabel=-',
		'headers=hide',
		'link=none',
		'limit=1',
	}

	local res = smw.ask( ask )
	if type( res ) ~= "table" or type( res[ 1 ] ) ~= "table" then
		return ""
	end

	local v = res[ 1 ][ propName ]
	if type( v ) == "table" then
		return t_concat( v, "," )
	end
	if type( v ) == "string" then
		return v
	end
	return ""
end

local function emptyCard( msg )
	return '<div class="carte-vide">' .. msg .. '</div>'
end

local function renderCards( listStr, pairDelim, fieldDelim, emptyHtml, sourceId )
	listStr = trim( listStr )
	if listStr == "" then
		return emptyHtml
	end

	local pairsList = splitListCached( listStr, pairDelim )
	if #pairsList == 0 then
		return emptyHtml
	end

	local out = {}
	local n = 0

	if not sourceId then
		--	Optim : ne split que si le délimiteur existe
		for i = 1, #pairsList do
			local rawPair = pairsList[ i ]
			if rawPair and rawPair ~= "" then
				local pageTitle, label

				local iDelim, jDelim = str_find( rawPair, fieldDelim, 1, true )
				if iDelim then
					pageTitle = trim( str_sub( rawPair, 1, iDelim - 1 ) )
					label = trim( str_sub( rawPair, jDelim + 1 ) )
				else
					pageTitle = trim( rawPair )
					label = ""
				end

				if pageTitle ~= "" then
					local display = ( label ~= "" ) and label or pageTitle
					n = n + 1
					out[ n ] = '<div class="argument-title--map wk-icon argument-icon">[[' .. pageTitle .. '|' .. display .. ']]</div>'
				end
			end
		end
		return ( n > 0 ) and t_concat( out ) or emptyHtml
	end

	for i = 1, #pairsList do
		local rawPair = pairsList[ i ]
		if rawPair and rawPair ~= "" then
			local pageTitle, label = splitPairOnce( rawPair, fieldDelim )
			if pageTitle ~= "" then
				local display = ( label ~= "" ) and label or pageTitle
				local itemId = idCached( pageTitle )

				local link
				if itemId and itemId == sourceId then
					link = "'''" .. display .. "'''"
				else
					link = '[[' .. pageTitle .. '|' .. display .. ']]'
				end

				n = n + 1
				out[ n ] = '<div class="argument-title--map wk-icon argument-icon">' .. link .. '</div>'
			end
		end
	end

	return ( n > 0 ) and t_concat( out ) or emptyHtml
end

----------------------------------------------------------------------
--	Entrée
----------------------------------------------------------------------

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

	--	Langue : utilise le moteur central (args.lang / args.language sinon contentLanguage)
	local lang = WD_I18N.getLangFromArgs( args )

	local page = urldecodeMaybe( args[ 1 ] )
	if page == "" then
		return ""
	end

	local source = urldecodeMaybe( args[ 2 ] )
	local showArgs = trim( args[ 3 ] ) ~= ""

	--	I18N (ArgumentMap.* via domaines)
	local propMap		= msg( 'ArgumentMap.props', lang, 'arg_map' )

	local headPro		= msg( 'ArgumentMap.text', lang, 'arg_map_pro_label' )
	local headCon		= msg( 'ArgumentMap.text', lang, 'arg_map_con_label' )

	local headJust		= msg( 'ArgumentMap.text', lang, 'justifs_label' )
	local headObj		= msg( 'ArgumentMap.text', lang, 'objs_label' )

	local nonePro		= msg( 'ArgumentMap.text', lang, 'none_pro_args_msg_short' )
	local noneCon		= msg( 'ArgumentMap.text', lang, 'none_con_args_msg_short' )

	local noneJust		= msg( 'ArgumentMap.text', lang, 'none_justifications_msg' )
	local noneObj		= msg( 'ArgumentMap.text', lang, 'none_objections_msg' )

	local propProList	= msg( 'ArgumentMap.props', lang, 'pro_list' )
	local propConList	= msg( 'ArgumentMap.props', lang, 'con_list' )

	local propJustList	= msg( 'ArgumentMap.props', lang, 'justifs_list' )
	local propObjList	= msg( 'ArgumentMap.props', lang, 'objs_list' )

	--	Optim : emptyCard pré-calculé
	local emptyPro		= emptyCard( nonePro )
	local emptyCon		= emptyCard( noneCon )
	local emptyJust		= emptyCard( noneJust )
	local emptyObj		= emptyCard( noneObj )

	--	Sans “Source” : fallback historique (propriété SMW “argument map”)
	if source == "" then
		return smwGetProp( page, propMap )
	end

	local sourceId = idCached( source )

	if showArgs then
		local props = smwGetProps( page, { propProList, propConList } )
		local listPro = props[ propProList ] or ""
		local listCon = props[ propConList ] or ""

		local left = renderCards( listPro, '-;-', '⟬', emptyPro, sourceId )
		local right = renderCards( listCon, '-;-', '⟬', emptyCon, sourceId )

		return renderTable( headPro, headCon, left, right )
	end

	local props = smwGetProps( page, { propJustList, propObjList } )
	local listJust = props[ propJustList ] or ""
	local listObj = props[ propObjList ] or ""

	local left = renderCards( listJust, '⟭', '⟬', emptyJust, sourceId )
	local right = renderCards( listObj, '⟭', '⟬', emptyObj, sourceId )

	return renderTable( headJust, headObj, left, right )
end

return p