Aller au contenu

Module:Liste des cartes d'un Pokémon

De Poképédia

La documentation pour ce module peut être créée à Module:Liste des cartes d'un Pokémon/doc

local p = {}

local PROP_JEU = 'P139'
local PROP_EXTENSION = 'P140'
local PROP_SOUS_EXTENSION = 'P141'
local PROP_DATE_SORTIE = 'P142'
local PROP_NUMERO_CARTE = 'P143'
local PROP_NUMERO_MAX_SET = 'P144'
local PROP_SUJET_REPRESENTE = 'P145'
local PROP_SUJET_SECONDAIRE = 'P146'
local PROP_DATE_SORTIE_FRANCAISE = 'P27'

local DEFAULT_PRIMARY_LIMIT = 10
local DEFAULT_SECONDARY_LIMIT = 5

local JCC_ITEM = 'Q28777'
local JCCP_ITEM = 'Q10404'

local subject_list_module = nil

local DESC_ORDER = {
	{ property = PROP_DATE_SORTIE, kind = 'time', order = 'desc', nulls = 'last' },
	{ property = PROP_EXTENSION, kind = 'item-title', order = 'asc', nulls = 'last' },
	{ property = PROP_NUMERO_CARTE, kind = 'natural-string', order = 'asc', nulls = 'last' },
	{ kind = 'page-title', order = 'asc', nulls = 'last' },
}

local ASC_ORDER = {
	{ property = PROP_DATE_SORTIE, kind = 'time', order = 'asc', nulls = 'last' },
	{ property = PROP_EXTENSION, kind = 'item-title', order = 'asc', nulls = 'last' },
	{ property = PROP_NUMERO_CARTE, kind = 'natural-string', order = 'asc', nulls = 'last' },
	{ kind = 'page-title', order = 'asc', nulls = 'last' },
}

local FRENCH_MONTHS = {
	'janvier',
	'février',
	'mars',
	'avril',
	'mai',
	'juin',
	'juillet',
	'août',
	'septembre',
	'octobre',
	'novembre',
	'décembre',
}

local function trim( value )
	if value == nil then
		return ''
	end

	return mw.text.trim( tostring( value ) )
end

local function get_args( frame )
	local args = {}

	local function merge( source )
		if not source then
			return
		end
		for key, value in pairs( source ) do
			if value ~= nil then
				args[key] = value
			end
		end
	end

	merge( frame:getParent() and frame:getParent().args )
	merge( frame.args )

	return args
end

local function get_item_title_or_label( item_id )
	if not item_id or item_id == '' then
		return ''
	end

	return trim( mw.wikibase.getSitelink( item_id ) or mw.wikibase.getLabel( item_id ) or '' )
end

local function get_subject_context( args )
	local current_title = mw.title.getCurrentTitle().text
	local page_title = trim( args.page or args[1] )
	local item_id = trim( args.item )

	if item_id == '' then
		if page_title == '' then
			page_title = current_title
		end

		if page_title == current_title then
			item_id = mw.wikibase.getEntityIdForCurrentPage() or ''
		else
			item_id = mw.wikibase.getEntityIdForTitle( page_title ) or ''
		end
	end

	if page_title == '' and item_id ~= '' then
		page_title = get_item_title_or_label( item_id )
	end

	if page_title == '' then
		page_title = current_title
	end

	return {
		page_title = page_title,
		item_id = item_id ~= '' and item_id or nil,
	}
end

local function get_subject_shared()
	if not subject_list_module then
		local ok, module = pcall( require, "Module:Liste des cartes d'un sujet" )
		if ok and type( module ) == 'table' then
			subject_list_module = module
		end
	end

	local shared = subject_list_module and subject_list_module._shared
	if type( shared ) ~= 'table' then
		error( "Module:Liste des cartes d'un sujet indisponible." )
	end

	return shared
end

local function query_cards_for_item( property_id, item_id, limit, game_item_id, order_by )
	return get_subject_shared().query_cards_for_item( property_id, item_id, limit, game_item_id, order_by )
end

local function has_matching_cards( property_id, item_id, game_item_id )
	return get_subject_shared().has_matching_cards( property_id, item_id, game_item_id, DESC_ORDER )
end

local function trim_to_limit( cards, limit )
	return get_subject_shared().trim_to_limit( cards, limit )
end

local function render_card_tiles( frame, cards )
	return get_subject_shared().render_card_tiles( frame, cards )
end

local function format_french_date( time_value )
	if type( time_value ) ~= 'string' then
		return nil
	end

	local year, month, day = time_value:match( '^%+?(%-?%d+)%-(%d%d)%-(%d%d)T' )
	if not year then
		return nil
	end

	local month_index = tonumber( month )
	if not month_index or not FRENCH_MONTHS[month_index] then
		return nil
	end

	local day_number = tonumber( day ) or 0
	local day_text = tostring( day_number )
	if day_number == 1 then
		day_text = '1<sup>er</sup>'
	end

	return string.format( '%s %s %s', day_text, FRENCH_MONTHS[month_index], year )
end

local function get_first_time_value( item_id, property_id )
	if not item_id or item_id == '' then
		return nil
	end

	local ok, statements = pcall( mw.wikibase.getBestStatements, item_id, property_id )
	if not ok or type( statements ) ~= 'table' then
		return nil
	end

	for _, statement in ipairs( statements ) do
		local value = statement and statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value
		if type( value ) == 'table' and value.time then
			return value.time
		end
	end

	return nil
end

local function build_query_constraint( property_id, page_title )
	if property_id == PROP_SUJET_REPRESENTE then
		return string.format( '[[Sujet représenté::%s]]', page_title )
	end

	return string.format( '[[Sujet secondaire::%s]]', page_title )
end

local function render_query_link( frame, query_constraint, text, jeu )
	local args = {
		[1] = query_constraint,
		texte = text,
	}

	if jeu then
		args.jeu = jeu
	end

	return frame:expandTemplate {
		title = 'Requête JCC',
		args = args,
	}
end

local function render_associated_lists( frame, property_id, page_title, has_jcc, has_jccp )
	if not has_jcc or not has_jccp then
		return ''
	end

	local query_constraint = build_query_constraint( property_id, page_title )
	local jcc_link = render_query_link( frame, query_constraint, 'JCC', 'JCC' )
	local jccp_link = render_query_link( frame, query_constraint, 'JCC Pokémon Pocket', 'JCCP' )

	return '<div style="line-height:125%; padding:5px 0px"><b>Listes de cartes associées&nbsp;:</b> <span style="white-space:nowrap">'
		.. jcc_link .. ' • ' .. jccp_link .. '</span></div>'
end

local function render_view_all( frame, property_id, page_title, has_more )
	if not has_more then
		return ''
	end

	local query_constraint = build_query_constraint( property_id, page_title )
	local link = render_query_link( frame, query_constraint, '[Voir toutes les cartes]' )

	return '<div style="line-height:125%; padding:5px 0px">' .. link .. '</div>'
end

local function render_cards_block( frame, property_id, page_title, cards, has_more, has_jcc, has_jccp )
	return '<div style="text-align:center">'
		.. render_associated_lists( frame, property_id, page_title, has_jcc, has_jccp )
		.. render_card_tiles( frame, cards )
		.. render_view_all( frame, property_id, page_title, has_more )
		.. '</div>'
end

local function render_first_appearance( page_title, item_id )
	local cards = query_cards_for_item( PROP_SUJET_REPRESENTE, item_id, 1, nil, ASC_ORDER )
	local first_card = cards[1]
	if not first_card then
		return ''
	end

	local extension = first_card.extension_title
	if extension ~= '' then
		extension = string.format( '[[%s]]', extension )
	end

	local date_text = format_french_date(
		get_first_time_value( first_card.extension_item_id, PROP_DATE_SORTIE_FRANCAISE )
	)

	if date_text then
		return string.format(
			"%s apparaît pour la première fois dans l'extension %s, sortie le %s en France.",
			page_title,
			extension,
			date_text
		)
	end

	return string.format(
		"%s apparaît pour la première fois dans l'extension %s, jamais sortie en France.",
		page_title,
		extension
	)
end

function p.main( frame )
	local args = get_args( frame )
	local subject = get_subject_context( args )
	local page_title = subject.page_title ~= '' and subject.page_title or mw.title.getCurrentTitle().text

	if not subject.item_id then
		return page_title .. " n'apparaît pas dans le Jeu de Cartes à Collectionner."
	end

	local primary_cards = query_cards_for_item(
		PROP_SUJET_REPRESENTE,
		subject.item_id,
		DEFAULT_PRIMARY_LIMIT + 1,
		nil,
		DESC_ORDER
	)
	if #primary_cards == 0 then
		return page_title .. " n'apparaît pas dans le Jeu de Cartes à Collectionner."
	end

	local secondary_cards = query_cards_for_item(
		PROP_SUJET_SECONDAIRE,
		subject.item_id,
		DEFAULT_SECONDARY_LIMIT + 1,
		nil,
		DESC_ORDER
	)

	local primary_has_more = #primary_cards > DEFAULT_PRIMARY_LIMIT
	local secondary_has_more = #secondary_cards > DEFAULT_SECONDARY_LIMIT

	primary_cards = trim_to_limit( primary_cards, DEFAULT_PRIMARY_LIMIT )
	secondary_cards = trim_to_limit( secondary_cards, DEFAULT_SECONDARY_LIMIT )

	local output = {}
	local primary_has_jcc = has_matching_cards( PROP_SUJET_REPRESENTE, subject.item_id, JCC_ITEM )
	local primary_has_jccp = has_matching_cards( PROP_SUJET_REPRESENTE, subject.item_id, JCCP_ITEM )

	if #secondary_cards > 0 then
		output[#output + 1] = '<h3>Cartes représentant ' .. page_title .. '</h3>'
	end

	output[#output + 1] = render_first_appearance( page_title, subject.item_id )
	output[#output + 1] = render_cards_block(
		frame,
		PROP_SUJET_REPRESENTE,
		page_title,
		primary_cards,
		primary_has_more,
		primary_has_jcc,
		primary_has_jccp
	)

	if #secondary_cards > 0 then
		output[#output + 1] = "<h3>Apparitions sur d'autres cartes</h3>"
		output[#output + 1] = page_title .. " apparaît également sur les cartes suivantes&nbsp;:"
		output[#output + 1] = render_cards_block(
			frame,
			PROP_SUJET_SECONDAIRE,
			page_title,
			secondary_cards,
			secondary_has_more,
			has_matching_cards( PROP_SUJET_SECONDAIRE, subject.item_id, JCC_ITEM ),
			has_matching_cards( PROP_SUJET_SECONDAIRE, subject.item_id, JCCP_ITEM )
		)
	end

	return table.concat( output, '\n' )
end

return p