Modul:Spisak pjesama

Dokumentaciju za ovaj modul možete napraviti na stranici Modul:Spisak pjesama/dok

--
-- SPISAK PJESAMA
--

local p = {}

local args = {}
local root

-- Bosnian args mapping
local bs_args_map = {
	naslov              = 'headline',
	ukupno_trajanje     = 'total_length',
	['sakrij_sadržaj']  = 'collapsed',
	sve_napisao         = 'all_writing',
	sva_muzika          = 'all_music',
	svi_tekstovi        = 'all_lyrics',
	zasluge_pisanje     = 'writing_credits',
	zasluge_tekst       = 'lyrics_credits',
	zasluge_muzika      = 'music_credits',
	dodatna_kolona      = 'extra_column',
	naziv               = 'title',
	['bilješka']        = 'note',
	autor               = 'writer',
	tekst               = 'lyrics',
	muzika              = 'music',
	dodatna             = 'extra',
	trajanje            = 'length'
}

local bs_args_value_map = {
	['sakrij_sadržaj'] = {da = 'yes'},
	zasluge_pisanje = {da = 'yes'},
	zasluge_tekst   = {da = 'yes'},
	zasluge_muzika  = {da = 'yes'}
}
		

local function union(t1, t2, t3)
    -- Returns the union of the values of three tables, as a sequence.
    local vals = {}
    for k, v in pairs(t1) do
        vals[v] = true
    end
    for k, v in pairs(t2) do
        vals[v] = true
    end
	for k, v in pairs(t3) do
        vals[v] = true
    end
    local ret = {}
    for k, v in pairs(vals) do
        table.insert(ret, k)
    end
    return ret
end

local function getArgNums(prefix)
    -- Returns a table containing the numbers of the arguments that exist
    -- for the specified prefix. For example, if the prefix was 'data', and
    -- 'data1', 'data2', and 'data5' exist, it would return {1, 2, 5}.
    local nums = {}
    for k, v in pairs(args) do
        local num = tostring(k):match('^' .. prefix .. '([1-9]%d*)$')
        if num then table.insert(nums, tonumber(num)) end
    end
    table.sort(nums)
    return nums
end

local function renderHeadline()
	if args.headline or args.collapsed == 'yes' then
		local headline = root:tag('tr')
		
		local th = headline:tag('th')
			:addClass('tlheader')
			:addClass('mbox-text')
			:attr('colspan', '10')
			:css('text-align', 'left')
			:css('background-color', '#fff')
		if args.headline then
			th:wikitext(args.headline)
		else 
			th:wikitext('Spisak pjesama')
		end
		
		-- empty
		headline:tag('td')
			:addClass('mbox-empty-cell')
	end
end

local function renderHeader()
	
	local header = root:tag('tr')
		:css('background-color', '#eee')
	
	-- index	
	header:tag('th')
		:attr('scope', 'col')
		:addClass('tlheader')
		:css('width', '2em')
		:css('padding-left', '10px')
		:css('padding-right', '10px')
		:css('text-align', 'right')
		:wikitext('Br.')
		
	-- title
	local temp = 0
	if args.writing_credits == 'yes' then 
		temp = temp+1 
	else
		if args.lyrics_credits == 'yes' then temp = temp+1 end
		if args.music_credits == 'yes' then temp = temp+1 end
	end
	if args.extra_column then temp = temp+1 end
	
	local title = header:tag('th')
		:attr('scope', 'col')
		:addClass('tlheader')
		:css('text-align', 'left')
		:wikitext('Naziv')
	if temp == 0 then
		title:css('width', '100%')
	elseif temp == 1 then
		title:css('width', '60%')
	elseif temp == 2 then
		title:css('width', '40%')
	else 
		title:css('width', '30%')
	end
	
	-- writers
	if args.writing_credits == 'yes' then
		local writers = header:tag('th')
			:attr('scope', 'col')
			:addClass('tlheader')
			:css('text-align', 'left')
			:wikitext('Autor(i)')
		if args.extra_column then
			writers:css('width', '30%')
		else
			writers:css('width', '40%')
		end
	else 
		-- lyrics
		if args.lyrics_credits == 'yes' then
			local lyrics = header:tag('th')
				:attr('scope', 'col')
				:addClass('tlheader')
				:css('text-align', 'left')
				:wikitext('Tekst')
			temp = 0
			if args.music_credits == 'yes' then temp = temp+1 end
			if args.extra_column then temp = temp+1 end
			if temp == 0 then
				lyrics:css('width', '40%')
			elseif temp == 1 then
				lyrics:css('width', '30%')
			else 
				lyrics:css('width', '20%')
			end
		end
		-- music
		if args.music_credits == 'yes' then
			local lyrics = header:tag('th')
				:attr('scope', 'col')
				:addClass('tlheader')
				:css('text-align', 'left')
				:wikitext('Muzika')
			temp = 0
			if args.lyrics_credits == 'yes' then temp = temp+1 end
			if args.extra_column then temp = temp+1 end
			if temp == 0 then
				lyrics:css('width', '40%')
			elseif temp == 1 then
				lyrics:css('width', '30%')
			else 
				lyrics:css('width', '20%')
			end
		end
	end
	
	-- extra column
	if args.extra_column then
		local extra = header:tag('th')
			:attr('scope', 'col')
			:addClass('tlheader')
			:css('text-align', 'left')
			:wikitext(args.extra_column)
		temp = 0
		if args.writing_credits then
			temp = temp+1
		else
			if args.lyrics_credits == 'yes' then temp = temp+1 end
			if args.music_credits == 'yes' then temp = temp+1 end
		end
		if temp == 0 then
			extra:css('width', '40%')
		elseif temp == 1 then
			extra:css('width', '30%')
		else 
			extra:css('width', '20%')
		end
	end
	
	-- length
	header:tag('th')
		:attr('scope', 'col')
		:addClass('tlheader')
		:css('width', '4em')
		:css('padding-right', '10px')
		:css('text-align', 'right')
		:wikitext('Trajanje')
		
	-- empty
	header:tag('td')
		:addClass('mbox-empty-cell')
end

local function addRow(rowArgs)
	
	local row = root:tag('tr')
	
	-- background color
	if rowArgs.index % 2 == 0 then
		row:css('background-color', '#f7f7f7')
	else
		row:css('background-color', '#fff')
	end
	
	-- index
	row:tag('td')
		:css('padding-right', '10px')
		:css('text-align', 'right')
		:css('vertical-align', 'top')
		:wikitext(tostring(rowArgs.index))
		
	-- title
	local title = row:tag('td')
		:css('text-align', 'left')
		:css('vertical-align', 'top')
	if rowArgs.title then
		title:wikitext('"' .. rowArgs.title .. '"')
	else
		title:wikitext('bez imena')
	end
	
	-- note
	if rowArgs.note then
		title:wikitext(' ')
		title:tag('span')
			:css('font-size', '85%')
			:wikitext('(' .. rowArgs.note .. ')')
	end
	
	-- writer
	if args.writing_credits == 'yes' then
		local writer = row:tag('td')
			:css('vertical-align', 'top')
		if rowArgs.writer then
			writer:wikitext(rowArgs.writer)
		end
	else
		-- lyrics
		if args.lyrics_credits == 'yes' then
			local lyrics = row:tag('td')
				:css('vertical-align', 'top')
			if rowArgs.lyrics then
				lyrics:wikitext(rowArgs.lyrics)
			end
		end
		--music
		if args.music_credits == 'yes' then
			local music = row:tag('td')
				:css('vertical-align', 'top')
			if rowArgs.music then
				music:wikitext(rowArgs.music)
			end
		end
	end
	
	-- extra
	if args.extra_column then
		local extracolumn = row:tag('td')
			:css('vertical-align', 'top')
		if rowArgs.extra then
			extracolumn:wikitext(rowArgs.extra)
		end
	end
	
	-- length
	local length = row:tag('td')
		:css('padding-right', '10px')
		:css('text-align', 'right')
		:css('vertical-align', 'top')
	if rowArgs.length then
		length:wikitext(rowArgs.length)
	end
end

local function renderRows()
	-- Get the union of the title, note and length arguments number
	local rownums = union(getArgNums('title'), getArgNums('note'), getArgNums('length'))
	table.sort(rownums)
	
	local index = 0
	for k, num in ipairs(rownums) do
		index = index+1
		addRow({
			index  = index,
			title  = args['title' .. tostring(num)],
			note   = args['note' .. tostring(num)],
			length = args['length' .. tostring(num)],
			lyrics = args['lyrics' .. tostring(num)],
			music  = args['music' .. tostring(num)],
			writer = args['writer' .. tostring(num)],
			extra  = args['extra' .. tostring(num)]
		})
	end
end

local function renderTotalLength()
	if args.total_length then
		local row = root:tag('tr')
		
		local colspan = 2;
		if args.writing_credits == 'yes' then
			colspan = colspan+1
		else
			if args.lyrics_credits == 'yes' then colspan = colspan+1 end
			if args.music_credits == 'yes' then colspan = colspan+1 end
		end
		if args.extra_column then colspan = colspan+1 end
		
		local td = row:tag('td')
			:attr('align', 'right')
			:attr('colspan', tostring(colspan))
			:css('padding', '0')
		
		td:tag('div')
			:css('width', '8.5em')
			:css('text-align', 'left')
			:css('padding', '5px 0 5px 10px')
			:css('background-color', '#eee')
			:css('margin', '0')
			:tag('b')
				:wikitext('Ukupno trajanje:')
		
		row:tag('td')
			:css('text-align', 'right')
			:css('padding-right', '10px')
			:css('background-color', '#eee')
			:tag('b')
				:wikitext(args.total_length)
		
		-- empty
		row:tag('td')
			:addClass('mbox-empty-cell')
	end
end

local function _track_list()
	local html = mw.html.create()
	
	-- text above the table
	if args.all_writing then
		html:wikitext('Sve pjesme napisao/la i komponovao/la ' .. args.all_writing)
	else 
		if args.all_lyrics then
			html:wikitext('Sve tekstove napisao/la ' .. args.all_lyrics)
			if args.all_music then html:wikitext(', ') else html:wikitext('. ') end
		end
		if args.all_music then
			if args.all_lyrics then html:wikitext('s') else html:wikitext('S') end
			html:wikitext('vu muziku komponovao/la ' .. args.all_music)
		end
	end
	
	-- (table) root
	root = html:tag('table')
	
	root:addClass('tracklist')
	if args.collapsed == 'yes' then
		root:addClass('mw-collapsible mw-collapsed')
	end
	
	root:css('border-spacing', '0px')
	root:css('border-collapse', 'collapse')
	if args.collapsed == 'yes' then
		root:css('border', '#aaa 1px solid')
		root:css('padding', '3px')
	else
		root:css('padding', '4px')
	end
	
	renderHeadline()
	renderHeader()
	renderRows()
	renderTotalLength()
	
	return tostring(html)
end

-- Bosnian argument mapping function
local function preprocessBsMapping()
	-- Argument value mapping
	for k, v in pairs(origArgs) do
		if bs_args_value_map[k] then
			local mappedValues = bs_args_value_map[k]
			if mappedValues[v] then
				origArgs[k] = mappedValues[v]
			end
		end
	end

	-- Argument name mapping
	local new_origArgs = {}
	for k, v in pairs(origArgs) do
		local prefix, num = tostring(k):match('^(%D+)(%d*)$')
		if (bs_args_map[prefix] and origArgs[k]) then
			postfix = ''
			if num then
				postfix = num
			end
			new_key = bs_args_map[prefix] .. postfix
			new_origArgs[new_key] = origArgs[k]
	   	end
	end
	origArgs = new_origArgs
end

local function preprocessSingleArg(argName)
    -- If the argument exists and isn't blank, add it to the argument table.
    -- Blank arguments are treated as nil to match the behaviour of ParserFunctions.
    if (origArgs[argName] and origArgs[argName] ~= '') then
		args[argName] = origArgs[argName]
    end
end

local function preprocessArgs(prefixTable, step)
    -- Assign the parameters with the given prefixes to the args table, in order, in batches
    -- of the step size specified. This is to prevent references etc. from appearing in the
    -- wrong order. The prefixTable should be an array containing tables, each of which has
    -- two possible fields, a "prefix" string and a "depend" table. The function always parses
    -- parameters containing the "prefix" string, but only parses parameters in the "depend"
    -- table if the prefix parameter is present and non-blank.
    if type(prefixTable) ~= 'table' then
        error("Non-table value detected for the prefix table", 2)
    end
    if type(step) ~= 'number' then
        error("Invalid step value detected", 2)
    end
 
    -- Get arguments without a number suffix, and check for bad input.
    for i,v in ipairs(prefixTable) do
        if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
            error('Invalid input detected to preprocessArgs prefix table', 2)
        end
        preprocessSingleArg(v.prefix)
        -- Only parse the depend parameter if the prefix parameter is present and not blank.
        if args[v.prefix] and v.depend then
            for j, dependValue in ipairs(v.depend) do
                if type(dependValue) ~= 'string' then
                    error('Invalid "depend" parameter value detected in preprocessArgs')
                end
                preprocessSingleArg(dependValue)
            end
        end
    end
 
    -- Get arguments with number suffixes.
    local a = 1 -- Counter variable.
    local moreArgumentsExist = true
    while moreArgumentsExist == true do
        moreArgumentsExist = false
        for i = a, a + step - 1 do
            for j,v in ipairs(prefixTable) do
                local prefixArgName = v.prefix .. tostring(i)
                if origArgs[prefixArgName] then
                    moreArgumentsExist = true -- Do another loop if any arguments are found, even blank ones.
                    preprocessSingleArg(prefixArgName)
                end
                -- Process the depend table if the prefix argument is present and not blank, or
                -- we are processing "prefix1" and "prefix" is present and not blank, and
                -- if the depend table is present.
                if v.depend and (args[prefixArgName] or (i == 1 and args[v.prefix])) then
                    for j,dependValue in ipairs(v.depend) do
                        local dependArgName = dependValue .. tostring(i)
                        preprocessSingleArg(dependArgName)
                    end
                end
            end
        end
        a = a + step
    end
end

function p.track_list(frame)
	-- If called via #invoke, use the args passed into the invoking template.
    -- Otherwise, for testing purposes, assume args are being passed directly in.
    if frame == mw.getCurrentFrame() then
        origArgs = frame:getParent().args
    else
        origArgs = frame
    end
	
	preprocessBsMapping()
	
	preprocessSingleArg('all_writing')
	preprocessSingleArg('all_lyrics')
	preprocessSingleArg('all_music')
	preprocessSingleArg('collapsed')
	preprocessSingleArg('headline')
	preprocessSingleArg('writing_credits')
	preprocessSingleArg('lyrics_credits')
	preprocessSingleArg('music_credits')
	preprocessSingleArg('extra_column')
	preprocessArgs({
        {prefix = 'title'},
        {prefix = 'note'},
        {prefix = 'length'},
        {prefix = 'lyrics'},
        {prefix = 'music'},
        {prefix = 'writer'},
        {prefix = 'extra'}
    }, 120)
	preprocessSingleArg('total_length')
	
	return _track_list()
end

return p