Модуль:Index

Материал из Указатель частей и соединений РККА 1941-1945
Перейти к:навигация, поиск

Для документации этого модуля может быть создана страница Модуль:Index/doc

local p = {}

local global = mw.ext.luaglobal
local tools = require( 'Module:Tools' )
local cargo = mw.ext.cargo

--[[
старт: Запрос к БД, вытаскиваем всё в глобал
печать:
- заголовок таблицы
- сотня (диапазон номеров и как формируется — сплошным перебором или существующими номерами в указанном диапазоне
    проблемы: 101 номер, 90 почти подряд и 5 вразбивку)
	описывать отдельно каждую сотню мешает то, что их может быть неопределенно много
		варианты описания: 0-599/200 = все подряд по 200 штук, *300-5999/100 — существующие в указанном диапазоне
		сложные сотни? 0-49 подряд, потом разбивка

--]]

function p.Query( frame )
	local args = tools.checkargs( frame:getParent().args, {
			['категории'] = '', ['номера'] = '',
			['гвардия'] = '*', ['отд.'] = '*',
			['без вики-категории'] = 'нет',
		} )
	local cats = mw.text.split( args['категории'], ' *[,\n]+ *' )
	local request = {}
	if #cats == 1 and mw.ustring.sub( cats[1], 1, 4 ) == 'гв. ' then -- ради страниц категорий гв. минометов
--		cats[1] = mw.ustring.sub( cats[1], 5, -1 )
		args['гвардия'] = 'да'
	end
	for _, cat in ipairs( cats ) do
		if cat ~= '' then
			table.insert( request, 'class="' .. cat ..'"' )
		end
	end
	if #request == 0 then
		error( 'Не заданы категории для запроса' )
	end
	local noctg = require( 'Module:Yesno') ( args['без вики-категории'], true )
	request = '(' .. table.concat( request, ' OR ' ) .. ')'
	local guards = require( 'Module:Yesno') ( args['гвардия'], '*' )
	if guards ~= '*' then
		if guards then
			request = request .. ' AND guard=TRUE'
		else
			request = request .. ' AND guard IS NULL'
		end
	end
	local standalone = require( 'Module:Yesno') ( args['отд.'], '*' )
	if standalone ~= '*' then
		if standalone then
			request = request .. ' AND standalone=TRUE'
		else
			request = request .. ' AND standalone IS NULL'
		end
	end
	local qq = cargo.query( 'unitpages',
		'unit, class, first, last, special, number',
		{
			where   = request, -- .. ' AND (special is NULL OR special <> "a")',
			orderBy = 'number, class, special, unit',
			limit = 5000,
		} )
	if #qq == 0 then
		return '<p>Запрос вернул пустой результат.</p>'
	end

	local res = {}
	if not noctg then
		table.insert( res, '[[Category:' .. table.concat( cats, '|*]][[Category:' ) .. '|*]]' )
	end
	local blocksArray = args['номера']
	if blocksArray == 'текст' or blocksArray == 'текст+' then
		table.sort( qq, function ( a, b )
				local an, at = string.match( a.unit, '^(%d*) *(.+)$' )
				local bn, bt = string.match( b.unit, '^(%d*) *(.+)$' )
				if at < bt then
					return true
				elseif at == bt then
					return ('0'..an) < ('0'..bn)
				else
					return false
				end
			end )
		local common = ' ' .. cats[1]
		if blocksArray == 'текст+' then
			common = '!!!'
		end
		local lcommon = - #common
		for _, u in ipairs( qq ) do
			local txt = u.unit
			if string.sub( txt, lcommon, -1 ) == common then
				txt = string.sub( txt, 1, lcommon-1 )
			end

			table.insert( res, '<div class=idx-button-text>' .. '[[' .. u.unit
				.. '|<span style=color:black>'.. txt .. '</span>]]</div>' )
		end
		return table.concat( res )
	end


	-- это всё фиктивный  кусок, потому что блок всегда один
	blocksArray = mw.text.split( blocksArray, '%s*;%s*' )
	local currentBlock = 0
	local block
	local function newBlock()
		currentBlock = currentBlock + 1
		if blocksArray[currentBlock] then
			local arr = mw.text.split( blocksArray[currentBlock], '%s*,%s*' )
			block = {}
			for _, u in ipairs( arr ) do
				local x, y, z
				if tonumber( u ) then
					x, y, z = '', u, u
				else
					x, y, z = string.match( u, '^(%*?)(%d+)%-(%d+)$' )
					if not x then
						error( 'Кривой диапазон' )
					end
				end
				y, z = tonumber( y ), tonumber( z )
				if y > z then
					error( 'Кривой диапазон' )
				end
				table.insert( block, { tonumber( y ), tonumber( z ), x ~= '*' } )
			end
			return block
		end
	end

	newBlock()
	table.insert( block, 1, { -3, -1, false } )
	table.insert( block, {99998, 99999, false } )
	local currentDiap = 1
	local delta = 0
	local outres = {  }
	local minnum = 999999
	local maxnum = -1
	local function toPrint( unit, number )
		if number > maxnum then
			maxnum = number
		end
		if number < minnum then
			minnum = number
		end

		if outres[number] then
			table.insert( outres[number], unit )
		else
			outres[number] = { unit }
		end
	end

--	do return mw.dumpObject( block ) end




	for _, unit in ipairs( qq ) do
-- если предыдущий блок должен был завершиться, то он уже завершен
-- (блок завершается либо по фиксированному числу элементов (но продлевается,
-- если осталось 20 или менее элементов), либо по «;» в списке номеров)
--
-- пока блоки не трогаем, считаем, что блок единственный.
-- текущим элементом раскладки является диапазон block[currentDiap] со сдвигом delta от начала.
-- это означает, что в эту позицию мы уже что-то выводили

-- если текущий unit имеет номер меньше текущей раскладки, то мы «аварийно» его выводим
		local num = unit.number
		if num == '' then
			num = 0
		else
			num = tonumber( num )
		end
		if num < block[currentDiap][1] + delta then
			unit.warning = 'regular' --'over'
			toPrint( unit, num )
		elseif num == block[currentDiap][1] + delta then
			toPrint( unit, num )
		else
			for diap = currentDiap, #block do
				if num <= block[diap][2] then
					if diap ~= currentDiap then
						delta = 0
					else
						delta = delta+1
					end
					currentDiap = diap
					break
				end

				if block[diap][3] then
					local start
					if diap == currentDiap then
						start = delta + 1
					else
						start = 0
					end
					for i = block[diap][1] + start, block[diap][2] do
						toPrint( { warning = 'empty' }, i )
					end
				end
			end
			-- мы в нужном блоке
			if block[currentDiap][3] then
				for i = block[currentDiap][1]+delta, num - 1 do
					toPrint( { warning = 'empty' }, i )
				end
			end
			delta = num - block[currentDiap][1]
			toPrint( unit, num )
		end
	end

--	do return mw.dumpObject( outres ) end
	for i = minnum, maxnum do
		local units = outres[i]
		local txt = i
		if i == 0 then
			txt = '<span style="letter-spacing:-0.3ex; font-style:italic;">&nbsp;<sup>б</sup>/<sub>№</sub></span>'
		end
		if units then
			if #units == 1 and ( i ~= 0 or units[1].warning == 'empty' )then
				if units[1].warning == 'empty' then

					table.insert( res ,
						'<div class=idx-button-empty>'
						.. '<span style="font-size:120%; margin:0">' .. txt .. '</span>'
						.. '</div>' )
				else
					table.insert( res ,
						'<div class=idx-button-' .. ( units[1].warning or 'regular' ) .. '>'
						.. '<span style="font-size:120%; margin:0">[[' .. units[1].unit .. '|<span style=color:black>'.. txt .. '</span>]]</span>'
						.. '</div>' )
				end
			else
				table.insert( res , '<div class=dropdown style=display:inline-block>'
					.. '<div class="idx-button-' .. ( units[1].warning or 'regular' )
					.. ' dropdown-toggle" data-toggle="dropdown">'
					.. '<span style="font-size:120%; margin:0">'.. txt
					.. '<br><i class="fa fa-caret-down"></i></span>'
					.. '</div><div class="dropdown-menu idx-dropdown">' )
				local unitsA = {}
				for _, u in ipairs( units ) do
					local pre, post = '', ''
					if u.special == 'a' then
						pre = '<i>'
						post = '</i>&nbsp;<i class="fas fa-share" title="Альтернативное наименование"></i>'
					elseif u.special == 'm' then
						pre = '<i>'
						post = '</i>&nbsp;<i class="fa fa-random" title="Разрешение неоднозначного наименования"></i>'
					end
					table.insert( unitsA, '<p>' .. pre .. '[[' .. u.unit .. ']]' .. post .. '</p>' )
				end
				table.insert( res, table.concat( unitsA ) )
				table.insert( res, '</div></div>' )
			end
		end
	end
	return table.concat( res )
end



return p