Module:Discographie

Aller à la navigation Aller à la recherche
 Documentation[modifier] [purger]

Le module : Truc sert à…

-- 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