Модуль:Песочница/CupIvan/треклист/песочница

Материал из Википедии — свободной энциклопедии
Перейти к навигации Перейти к поиску
Документация
local time = require('Модуль:Песочница/CupIvan/время/песочница')
local css  = 'Модуль:Песочница/CupIvan/треклист/style.css' -- FIXME: перенести в основной файл

local p = {}

-- генерация HTML разметки треклиста
function make_html(t)
	if not t.width then t.width = '100%' end
	if not t.columns then t.columns = {number = 1, title = 1, length = 1} end
	-- названия колонок
	if not t.title  then t.title  = 'Название' end
	if not t.author then t.author = 'Автор' end
	if not t.lyrics then t.lyrics = 'Слова' end
	if not t.music  then t.music  = 'Музыка' end
	if not t.extra  then t.extra  = '' end
	if not t.length then t.length = 'Длительность' end

	local html = mw.html.create('table')
	html:addClass('wikitable ts-Tracklist')
	if t.collapsed then html:addClass('mw-collapsible mw-collapsed') end
	html:css('width', t.width)

	if t.headline then
		html:tag('caption'):wikitext(t.headline)
	end

	local numExtraColumns = 0
	for k, v in pairs({ 'author', 'lyrics', 'music', 'extra'})
	do if t.columns[v] then numExtraColumns = numExtraColumns + 1 end end

	local w = { title='100%', other=0 }
	if numExtraColumns == 1 then w = { title='60%', other='40%' } end
	if numExtraColumns == 2 then w = { title='40%', other='30%' } end
	if numExtraColumns == 3 then w = { title='30%', other='20%' } end
	if numExtraColumns == 4 then w = { title='30%', other='15%' } end

	local tr = html:tag('tr')
	if t.columns.number then tr:tag('th'):attr('scope', 'col'):addClass('number')   :wikitext('№');      end
	if t.columns.title  then tr:tag('th'):attr('scope', 'col'):wikitext(t.title);  end
	if t.columns.author then tr:tag('th'):attr('scope', 'col'):css('width', w.other):wikitext(t.author); end
	if t.columns.lyrics then tr:tag('th'):attr('scope', 'col'):css('width', w.other):wikitext(t.lyrics); end
	if t.columns.music  then tr:tag('th'):attr('scope', 'col'):css('width', w.other):wikitext(t.music);  end
	if t.columns.extra  then tr:tag('th'):attr('scope', 'col'):css('width', w.other):wikitext(t.extra);  end
	if t.columns.length then tr:tag('th'):attr('scope', 'col'):addClass('length')   :wikitext(t.length); end
	local numColumns = table.getn(tr.nodes)

	local total_length = 0

	for n, a in pairs(t.tracks)
	do
		if t.side == nil or not t.side or t.side == a.side then
			local title = ''
			if a.title then
				if a.title == '' then title = "''Без названия''" else title = '«'..a.title..'»' end
			end
			if a.note then title = title .. ' <small>('..a.note..')</small>' end
			local tr = html:tag('tr')
			if t.columns.number then tr:tag('td'):wikitext(a.number..'.'):addClass('number') end
			if t.columns.title  then tr:tag('td'):wikitext(title) end
			if t.columns.author then tr:tag('td'):wikitext(a.author) end
			if t.columns.lyrics then tr:tag('td'):wikitext(a.lyrics) end
			if t.columns.music  then tr:tag('td'):wikitext(a.music)  end
			if t.columns.extra  then tr:tag('td'):wikitext(a.extra) end
			if t.columns.length then tr:tag('td'):wikitext(time.formatToString(a.length, "short")):addClass('length') end
			if a.length then total_length = total_length + a.length end
		end
	end
	
	if t.columns.length then
		if t.total_length ~= nil then total_length = time.stringToSeconds(t.total_length) end
		html:tag('tr'):tag('td'):attr('colspan', numColumns)
			:addClass('total'):wikitext(time.formatToString(total_length, "long"))
	end

	local st = ''
	st = st .. mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Шаблон:Tracklist/styles.css'}}
	st = st .. mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = css }} -- FIXME: перенести в основной файл

	if t.all_writing then st = st .. 'Слова и музыка всех песен ' .. t.all_writing .. '. ' end
	if t.all_lyrics  then st = st .. 'Все тексты написаны ' .. t.all_lyrics .. '. ' end
	if t.all_music   then st = st .. 'Вся музыка написана ' .. t.all_music .. '. ' end

	st = st .. tostring(html)

	return st
end

-- загрузка данных из шаблона
function p.tracks(frame)
	local t, columns = {}, {}

	t = frame.args; t.tracks={}; t.columns={}

	if not t.start then t.start = 1 end
	t.columns.number = 1 -- показываем колонку с номером

	-- формируем таблицу с данными
	local i = 1
	local lineNumber, columnNumber = 0, 0
	while frame.args[i] ~= nil
	do
		local value = mw.text.trim(frame.args[i])
		if frame.args[i] == "" then lineNumber = lineNumber + 1; columnNumber = 1 end
		if lineNumber == 1
		then
			columns[columnNumber] = value
			t.columns[value] = 1
		else
			if t.tracks[lineNumber] == nil then t.tracks[lineNumber] = {number = lineNumber-1+t.start-1} end
			if columns[columnNumber] == 'length' then value = time.stringToSeconds(value) end
			t.tracks[lineNumber][columns[columnNumber]] = value
		end
		columnNumber = columnNumber + 1
		i = i + 1
	end

	-- данные в старом формате (обратная совместимость)
	local i = 1
	while (frame.args['title'..i] ~= nil) or (i < 30)
	do
		local x = 'title'
		if frame.args[x..i] ~= nil then
			t.tracks[i] = {number = tonumber(i), title = frame.args[x..i]}; t.columns[x] = 1
			x = 'note';   if frame.args[x..i] ~= nil then t.columns[x] = 1; t.tracks[i][x] = frame.args[x..i] end
			x = 'writer'; if frame.args[x..i] ~= nil then t.columns[x] = 1; t.tracks[i][x] = frame.args[x..i] end
			x = 'lyrics'; if frame.args[x..i] ~= nil then t.columns[x] = 1; t.tracks[i][x] = frame.args[x..i] end
			x = 'music';  if frame.args[x..i] ~= nil then t.columns[x] = 1; t.tracks[i][x] = frame.args[x..i] end
			x = 'extra';  if frame.args[x..i] ~= nil then t.columns[x] = 1; t.tracks[i][x] = frame.args[x..i] end
			x = 'length'; if frame.args[x..i] ~= nil then t.columns[x] = 1; t.tracks[i][x] = time.stringToSeconds(frame.args[x..i]) end
		end
		i = i + 1
	end
	return make_html(t)
end

-- загрузка данных из wikidata
function p.wikidata(frame)
	local from = frame.args.from
	local st = ''
	local entity = mw.wikibase.getEntity(from)
	local tracks = entity['claims']['P658']
	local t = {tracks={}, columns={ title=1 }}
	local numSides = 1

	-- если задано количество - генерируем полный список треков
	local numParts = entity['claims']['P2635']
	if numParts then
		for k, a in pairs(numParts)
		do
			if a['mainsnak']['datavalue']['value']['unit'] == 'http://www.wikidata.org/entity/Q7302866'
			then
				local N = tonumber(a['mainsnak']['datavalue']['value']['amount'])
				for i=1,N do t.tracks[i]={ number=i } end
			end
		end
	end

	for k1, a1 in pairs(tracks)
	do
		local track = {}

		track['title'] = entityTitle(a1['mainsnak']['datavalue']['value']['id'])
		number = k1

		setDefaultPerson(t, track, 'lyrics', a1, 'P676')
		setDefaultPerson(t, track, 'music',  a1, 'P86')
		setDefaultPerson(t, track, 'author', a1, 'P50')

		for k2, a2 in pairs(a1['qualifiers'])
		do
			if k2 == 'P518' then -- сторона диска
				if a2[1]['datavalue']['value']['id'] == 'Q3827523'  then track['side'] = 1 end
				if a2[1]['datavalue']['value']['id'] == 'Q13432985' then track['side'] = 2; numSides = 2 end
			end
			if k2 == 'P1545' then -- номер трека
				track['number'] = tonumber(a2[1]['datavalue']['value'])
				t.columns.number = 1
				number = tonumber(track['number'])
			end
			if k2 == 'P2047' then -- длительность
				local seconds = tonumber(a2[1]['datavalue']['value']['amount'])
				track['length'] = seconds
				t.columns.length = 1
			end
			if k2 == 'P175' then -- исполнитель
				track['extra']  = _peoples(a2)
				t.columns.extra = 1
				t.extra = 'Исполнитель'
			end
			if k2 == 'P676' then -- автор слов
				track['lyrics']  = _peoples(a2)
				t.columns.lyrics = 1
			end
			if k2 == 'P86' then -- композитор
				track['music']  = _peoples(a2)
				t.columns.music = 1
			end
			if k2 == 'P50' then -- автор
				track['author'] = _peoples(a2)
				t.columns.author = 1
			end
		end

		t.tracks[number] = track
	end

	if numSides == 1 then return make_html(t) end

	local st = ''
	for i = 1, numSides do
		t.headline = 'Сторона ' .. i
		t.side = i
		st = st .. make_html(t)
	end
	return st
end

-- список авторов произведения
function _peoples(a)
	local st = ''
	for k, v in pairs(a)
	do
		if st ~= '' then st = st .. ', ' end
		st = st .. entityPersonName(v['datavalue']['value']['id'])
	end
	return st
end

-- фамилия и имя человека
function entityPersonName(Q)
	local entity = mw.wikibase.getEntity(Q)
	local shortName = _property(entity, 'P1813')
	if shortName == '' then shortName = _property(entity, 'P735')..'&nbsp;'.._property(entity, 'P734') end
	local name = entityUrl(Q)
	if shortName ~= '' then
		if name == '' then name = shortName else name = name..'|'..shortName end
	end
	return '[['..name..']]'
end

-- URL записи в wikipedia
function entityUrl(Q)
	local entity = mw.wikibase.getEntity(Q)
	if not entity then return '' end
	if entity['sitelinks']['ruwiki'] ~= nil then return ':ru:'..entity['sitelinks']['ruwiki']['title'] end
	if entity['sitelinks']['enwiki'] ~= nil then return ':en:'..entity['sitelinks']['enwiki']['title'] end
	return ''
end

-- заголовок записи
function entityTitle(Q)
	local entity = mw.wikibase.getEntity(Q)
	if not entity then return '' end
	if entity['labels']['ru'] ~= nil then return entity['labels']['ru']['value'] end
	if entity['labels']['en'] ~= nil then return entity['labels']['en']['value'] end
end

function _property(a, P)
	local claim = a.claims[P]
	if not claim then return '' end
	local v = claim[1]['mainsnak']['datavalue']['value']
	if v.text then return v.text end
	return entityTitle(v.id)
end

function setDefaultPerson(t, track, field, a, P)
	local entity = mw.wikibase.getEntity(a['mainsnak']['datavalue']['value']['id'])
	local claim = entity.claims[P]
	if not claim then return end
	local Q = claim[1]['mainsnak']['datavalue']['value']['id']
	track[field] = entityPersonName(Q)
	t.columns[field] = 1
end

return p