Module:Track listing
Appearance
![]() | This Lua module is used on approximately 116,000 pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
![]() | This module uses TemplateStyles: |
![]() | This module depends on the following other modules: |
![]() | This module is used by one or more bots in their standard operation. Any breaking changes to this module, including moving it or nominating it for deletion, must be communicated in advance to the bot operator(s). The relevant bots are: User:cewbot/log/20201008/configuration. |
This module implements {{track listing}}. Please see the template page for documentation.
-- This module implements [[Template:Track listing]]
local yesno = require('Module:Yesno')
--------------------------------------------------------------------------------
-- Track class
--------------------------------------------------------------------------------
local Track = {}
Track.__index = Track
Track.fields = {
number = true,
title = true,
note = true,
length = true,
lyrics = true,
music = true,
writer = true,
extra = true,
}
function Track.new(data)
local self = setmetatable({}, Track)
for field in pairs(Track.fields) do
self[field] = data[field]
end
self.number = assert(tonumber(self.number))
return self
end
function Track:getLyricsCredit()
return this.lyrics
end
function Track:getMusicCredit()
return this.music
end
function Track:getWriterCredit()
return this.writer
end
function Track:getExtraField()
return this.extra
end
function Track:exportHtml()
local row = mw.html.create('tr')
row:css('background-color', data.color)
-- Track number
row:tag('td')
:css('padding-right', '10px')
:css('text-align', 'right')
:css('vertical-align', 'top')
:wikitext(self.number .. '.')
-- Title
do
local title_cell = row:tag('td')
title_cell
:css('text-align', 'left')
:css('vertical-align', 'top')
:wikitext(self.title and string.format('"%s"', self.title) or 'Untitled')
:wikitext(' ')
if self.note then
title_cell:tag('span')
:css('font-size', '85%')
:wikitext(string.format('(%s)', self.note))
else
title_cell:wikitext(' ')
end
end
if self.writing_credits then
local wc_cell = row:tag('td')
wc_cell
:css('vertical-align', 'top')
:wikitext()
end
return row
end
--------------------------------------------------------------------------------
-- TrackListing class
--------------------------------------------------------------------------------
local TrackListing = {}
TrackListing.__index = TrackListing
TrackListing.fields = {
all_writing = true,
all_lyrics = true,
all_music = true,
collapsed = true,
headline = true,
extra_column = true,
total_length = true,
}
TrackListing.deprecatedFields = {
writing_credits = true,
lyrics_credits = true,
music_credits = true,
}
function TrackListing.new(data)
local self = setmetatable({}, TrackListing)
-- Add properties
for field in pairs(TrackListing.fields) do
self[field] = data[field]
end
-- Make track objects
self.tracks = {}
for i, trackData in ipairs(data.tracks or {}) do
table.insert(self.tracks, Track.new(trackData))
end
-- Find which of the optional columns we have.
-- We could just check every column for every track object, but that would
-- be no fun^H^H^H^H^H^H inefficient, so we use four different strategies
-- to try and check only as many columns and track objects as necessary.
do
local optionalColumns = {}
local columnMethods = {
lyrics = 'getLyricsCredit',
music = 'getMusicCredit',
writer = 'getWriterCredit',
extra = 'getExtraField',
}
local doneWriterCheck = false
for i, trackObj in ipairs(self.tracks) do
for column, method in pairs(columnMethods) do
if trackObj[method](trackObj) then
optionalColumns[column] = true
columnMethods[column] = nil
end
end
if not doneWriterCheck and optionalColumns.writer then
doneWriterCheck = true
optionalColumns.lyrics = nil
optionalColumns.music = nil
columnMethods.lyrics = nil
columnMethods.music = nil
end
if not next(columnMethods) then
break
end
end
self.optionalColumns = optionalColumns
end
-- Count the number of optional columns.
self.nOptionalColumns = 0
for k in pairs(self.optionalColumns) do
self.nOptionalColumns = self.nOptionalColumns + 1
end
return self
end
--------------------------------------------------------------------------------
-- Exports
--------------------------------------------------------------------------------
local p = {}
function p._main(args)
-- Process numerical args so that we can iterate through them.
local data, tracks = {}, {}
for k, v in pairs(args) do
if type(k) == 'string' then
local prefix, num = k:match('^(%D.-)(%d+)$')
if prefix and Track.fields[prefix] and (num == '0' or num:sub(1, 1) ~= '0') then
-- Allow numbers like 0, 1, 2 ..., but not 00, 01, 02...,
-- 000, 001, 002... etc.
num = tonumber(num)
tracks[num] = tracks[num] or {}
tracks[num][prefix] = v
else
data[k] = v
end
end
end
data.tracks = (function (t)
-- Compress sparse array
local ret = {}
for num, trackData in pairs(t) do
trackData.number = num
table.insert(ret, trackData)
end
table.sort(ret, function (t1, t2)
return t1.number < t2.number
end)
return ret
end)(tracks)
return tostring(TrackListing.new(data))
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Track listing'
})
return p._main(args)
end
return p