Module:Discographie

 Documentation[voir] [modifier] [historique] [purger]

Ce module implémente les modèles {{Discographie des albums}} et {{Discographie des chansons}}. Voir la documentation des modèles pour les instructions d'utilisation. Le module produit un tableau discographique avec pour chaque ligne des informations détaillées de l'album ou d'une chanson. Il permet d'uniformiser et de simplifier la mise en forme des articles.

Fonctions exportables modifier

  • main(frame) – Fonction implémentant le modèle {{Discographie des albums}} et {{Discographie des chansons}} – à appeler avec #invoke.
  • _main(args, classType) – Fonction qui peut être appelée dans un autre module avec require(). Ceci est une bonne pratique d'appeler cette fonction dans un autre module car cela permet d'omettre certains champs de l'objet frame, ce qui améliore les performances et simplifie la gestion des arguments. Le paramètre classType définit avec l'argument :
    • 'album' importera la discographie pour les albums,
    • 'chanson' importera la discographie pour les chansons.

Voir aussi modifier

-- Ce module implémente les modèles {{Discographie des albums}} et {{Discographie des chansons}}.

-- luacheck: globals mw

local p = {}

local cfg = {
	header = 'Liste des titres, avec positions dans les classements',
	headerWithAll = ', ventes cumulées et certifications',
	headerWithSale = ' et ventes cumulées',
	headerWithCertif = ' et certifications',
	title = 'Titre',
	details = "Détails de l'album",
	year = 'Année',
	position = 'Meilleure position',
	sale = 'Ventes',
	certif = '[[Disque de certification|Certifications]]',
	album = 'Album',
	footer = "« — » indique que le titre n'est pas sorti ou classé dans le pays.",
	prefix = {
		chart = 'pays',
		ref = 'ref',

		title = 'titre',
		option = 'option',
		details = 'détails',
		year = 'année',
		yearn = 'annéen',
		position = 'position',
		sale = 'vente',
		certif = 'certif',
		album = 'album',
		albumn = 'albumn'
	}
}

local function getArgNums(args, prefix)
	local nums = {}
	for k, _ in pairs(args) do
		local num = k:match('^' .. prefix .. '([1-9]%d*)$')
		if num then
			table.insert(nums, tonumber(num))
		end
	end
	table.sort(nums)
	return nums
end

local Discography = {}
Discography.__index = Discography

function Discography.new(args, cfg, classType)
	args = args or {}

	local fields = {
		args = args,
		cfg = cfg,
		isAlbumType = classType == 'album',
		root = mw.html.create('table')
			:addClass('wikitable')
			:css('text-align', 'center'),
		chartNums = getArgNums(args, cfg.prefix.chart),
		existsSale = #getArgNums(args, cfg.prefix.sale) > 0,
		existsCertif = #getArgNums(args, cfg.prefix.certif) > 0
	}
	return setmetatable(fields, Discography)
end

function Discography:__tostring()
	return tostring(self.root)
end

local function createTag(root, tag, text, attributes, styles)
	root:tag(tag):attr(attributes or {}):css(styles or {}):wikitext(text)
end

local function createTagIf(exist, root, tag, text, attributes, styles)
	if exist then createTag(root, tag, text, attributes, styles) end
end

function Discography:buildHeader()
	local args = self.args
	local cfg = self.cfg

	-- Create titles header.
	local titlesHeader = mw.html.create('tr')
	local attr = { scope = 'col', rowspan = '2' }
	local attrPosition = { scope = 'col', colspan = #self.chartNums }
	createTag(titlesHeader, 'th', cfg.title, attr)
	createTag(titlesHeader, 'th', self.isAlbumType and cfg.details or cfg.year, attr)
	createTag(titlesHeader, 'th', cfg.position, attrPosition)
	createTagIf(self.existsSale, titlesHeader, 'th', cfg.sale, attr)
	createTagIf(self.existsCertif, titlesHeader, 'th', cfg.certif, attr)
	createTagIf(not self.isAlbumType, titlesHeader, 'th', cfg.album, attr)

	-- Create charts header.
	local chartsHeader = mw.html.create('tr')
	local attr = { scope = 'col' }
	local css = { width = '2em', ['font-size'] = '90%' }
	for _, chartNum in pairs(self.chartNums) do
		local text = args[cfg.prefix.chart .. chartNum]
			.. '<br>'
			.. (args[cfg.prefix.ref .. chartNum] or '')
		createTag(chartsHeader, 'th', text, attr, css)
	end

	self.root
		:tag('caption')
		:wikitext(self.existsCertif and self.existsSale
			and cfg.header .. cfg.headerWithAll
			or self.existsCertif and cfg.header .. cfg.headerWithCertif
			or self.existsSale and cfg.header .. cfg.headerWithSale
			or cfg.header)
		:done()
		:node(titlesHeader)
		:node(chartsHeader)
	return self
end

local function optionTitle(optionValue)
	if not optionValue then
		return ''
	end
	return '<br><span style="font-size:89%">(' .. optionValue .. ')</span>'
end

local function splitBySemicolon(text)
	local res = {}
	if text then
		for match in text:gmatch('([^;]+)') do
			table.insert(res, mw.text.trim(match))
		end
	end
	return res
end

function Discography:buildRow(titleNum, args, prefix, css)
	local root = mw.html.create('tr')

	-- Create title column.
	local text = args[prefix.title .. titleNum]
		.. optionTitle(args[prefix.option .. titleNum])
	createTag(root, 'td', text, {}, css)

	-- Create album details column.
	-- Album type only.
	local text = args[prefix.details .. titleNum]
	text = text and '\n' .. text
	createTagIf(self.isAlbumType, root, 'td', text, {}, css)

	-- Create year column only if the previous yearn is not found.
	-- Song type only.
	local attr = { rowspan = args[prefix.yearn .. titleNum] or 1 }
	local text = args[prefix.year .. titleNum]
	createTagIf(text and not self.isAlbumType, root, 'td', text, attr)

	-- Create chart position columns.
	local positions = splitBySemicolon(args[prefix.position .. titleNum])
	for chartNum = 1, #self.chartNums do
		root:tag('td'):wikitext(positions[chartNum] or '—'):done()
	end

	-- Create optional sale column.
	local text = args[prefix.sale .. titleNum]
	text = text and '\n' .. text
	createTagIf(self.existsSale, root, 'td', text, {}, css)

	-- Create optional certification column.
	local text = args[prefix.certif .. titleNum]
	text = text and '\n' .. text
	createTagIf(self.existsCertif, root, 'td', text, {}, css)

	-- Create album column only if the previous yearn is not found.
	-- Song type only.
	local attr = { rowspan = args[prefix.albumn .. titleNum] or 1 }
	local text = args[prefix.album .. titleNum]
	createTagIf(text and not self.isAlbumType, root, 'td', text, attr)

	return root
end

function Discography:buildContent()
	local args = self.args
	local prefix = self.cfg.prefix
	local css = { ['text-align'] = 'left' }

	for _, titleNum in pairs(getArgNums(args, prefix.title)) do
		local currentRoot = self:buildRow(titleNum, args, prefix, css)
		self.root:node(currentRoot)
	end

	return self
end

function Discography:buildFooter()
	local rowNo = #self.chartNums
		+ (self.isAlbumType and 2 or 3)
		+ (self.existsCertif and 1 or 0)
		+ (self.existsSale and 1 or 0)
	self.root
		:tag('tr')
		:tag('td')
		:attr('colspan', rowNo)
		:css('font-size', '90%')
		:wikitext(self.cfg.footer)
		:done()
	return self
end

-- Access in the module space.
function p._main(args, classType)
	local discography = Discography.new(args, cfg, classType)
	return tostring(discography:buildHeader():buildContent():buildFooter())
end

-- Access outside the module space.
function p.main(frame)
	local argsParent = frame:getParent().args
	local cleanArgs = {}
	for k, v in pairs(argsParent) do
		if type(k) == 'string' and v ~= '' then
			cleanArgs[k] = mw.text.trim(v)
		end
	end

	return p._main(cleanArgs, frame.args[1])
end

return p