Модуль:Tools

Материал из Кадровый состав НКВД 1935-1939
Перейти к: навигация, поиск

    Описание   


Набор вспомогательных функций для других модулей.

errorMsg

Форматирование сообщения об ошибке вызова шаблона.

text = errorMsg( tpt, errorTxt, errorAdvice )
  • tpt — имя шаблона (без префикса «Шаблон:»)
  • errorTxt — диагностика
  • errorAdvice — дополнительные сведения об ошибке («Используйте формат обращения ...»)

Функция возвращает строку, содержащее отформатированное сообщение и задание категории «Страницы с ошибкой вызова шаблона ...».

checkargs

Проверка и нормализация аргументов

modArgs, hasArg = tools.checkargs( args, names )
  • args — таблица аргументов
  • names — описание допустимых аргументов в формате: ключ_допустимого аргумента = значение_по_умолчанию

Если значение_по_умолчанию равно true, то это означает, что соответствующий аргумент не имеет значения по умолчанию. В противном случае аргументы, ключи которых отсутствуют в исходной таблице args или имеют значение пустой строки, получают указанное значение_по_умолчанию.

При успешной проверке (в исходной таблице args нет элементов с ключами, отсутствующими в names) функция возвращает таблицу modArgs со всеми элементами (включая добавленные значения по умолчанию) и признак наличия элементов в исходной таблице аргументов. Последнее полезно, чтобы предупреждать ошибки, связанные с тем, что движок MediaWiki в ходе обработки страницы не интерпретирует повторно шаблоны без параметров; для повторного парсинга необходимо наличие у шаблона хотя бы пустого параметра.

При обнаружении в исходной таблице args первого же ключа отсутствующего в names, функция возвращает пару значений nil, лишний_ключ.

При возвращении значений (кроме значений по умолчанию) осуществляется нормализация: пробельные символы в начале и конце значения убираются, пустые значения превращаются в nil.

parseDate

Преобразование текстовой даты в стандартный внутренний формат

fdate, year, month, day = tools.parseDate( indate, border )
  • indate — дата в произвольном пользовательском формате
  • border — минимальный год (XIX века!) для дат, в которых год задан двумя цифрами

Возвращает fdate в формате гггг-мм-чч и числовые значения года, месяца и дня. Для неполных дат (год или месяц+год) текстовая строка укорочена, а вместо соответствующих числовых значений возвращается nil. При пустой дате на входе возвращает пустую строку. При ошибке возвращает nil.

reparseDate

Преобразование даты в стандартном внутреннем формате гггг-мм-чч в стандартный печатный формат (чч.мм.гггг)

text = tools.reparseDate( value )
  • value — дата в стандартном внутреннем формате

Обрабатывает в том числе и неполные даты (укороченные строки). При пустой дате отдает прочерк («—»).

textDate

Преобразование даты в стандартном внутреннем формате гггг-мм-чч в текстовый формат (с месяцем прописью).

text = tools.textDate( value, p )
  • value — дата в стандартном внутреннем формате
  • p — падеж ('i' — именительный (по умолчанию), 'g' — родительный)

Возвращает текст с месяцем прописью и словом «год» в конце. Падеж значим для неполных дат. При пустой дате отдает прочерк («—»).

phrase

Преобразование текста в предложение

mText = tools.phrase( text )

Преобразование текста в предложение (первая буква делается прописной, в конце добавляется точка.

noPhrase

Преобразование текста для использования внутри предложения

mText = tools.noPhrase( text )

Преобразование текста в не-предложение (первая буква делается строчной, завершающая точка, если она есть, упраздняется).

db

Криворуко сделанный (не через метатаблицу) доступ к данным

result = tools.db( base, elem, field )

Функция возвращает элемент (запись) таблицы db с ключом elem, а если задано имя поля field — соответствующее поле этой записи. Если запись содержит поле redirect, то происходит переадресация на элемент с указанным в поле redirect ключом.

commonParams

Обработка универсальных параметров шаблонов страниц персоналий

text = tools.commonParams( addendum, reference, source )
  • addendum — дополнение
  • reference — сноска
  • source — ссылка на первоисточник

Формирует текст для выходного потока.

При наличии сносок или источников обращается к модулю {{ RefTools}} , при наличии источников — к функции link модуля {{ Сайт}}  (через tools.formatIfUrl, см. ниже).

formatIfUrl

Преобразование параметра в красивую ссылку, если он представляет собой URL

text, noURL = tools.formatIfUrl( whatwherefrom, txt )
  • whatwherefrom — формат ссылки ('what' — сайт, 'where' — на сайте, 'from' — ???)
  • txt — обрабатываемый параметр

Возвращает параметр (если это был URL, то преобразованный) и true в качестве второго результата, если преобразования не было. Для преобразования вызывается функция link модуля {{ Сайт}} .

segment

Формирование ссылки на страницу места службы.

text = tools.segment( segmentName )
  • segmentName — наименование места службы

Функция возвращает ссылку в формате «[url segmentName]».

name

Добавление подкраски для индекса тезки в имени персоналии

text = tools.name( name, idx )
  • name — имя персоналии
  • idx — индекс тезки (если он не задан в первом параметре) или nil.

Функция возвращает текстовое представление имени с обрамлением индекса тезки тегом <span>.

splitName

Разбор имени, использованного для указания персоналии (на страницах документов и т. п.).

last, first, middle, idx, warning, normalized = tools.splitName( name, redlink )
  • name — имя персоналии
  • redlink — разбор выполняется для страницы несуществующего персонажа или страницы разрешения неоднозначности.

Возвращает разобранное по элементам (фамилия, имя, отчество, индекс тезки) имя. Для многословных элементов: граница фамилии определяется по запятой, а имя всегда считается однословным. Сведения об обнаруженных при разборе ошибках помещаются в массив текстовых строк warning (отсутствие ошибок — пустой массив). Последний элемент normalized, возвращаемый функцией, содержит имя, записанное в эталонной форме (инициалы с точками и проч.) без индекса тезки.

Используется модулями {{ Персона }} , {{ Упоминание }} , {{ Новый персонаж }} .

cargoString

Формирует условие для sql-запроса в зависимости от того, является ли значение пустым (IS NULL) или нет (= x).

text = tools.cargoString( value )
  • value — имя персоналии

Поскольку Cargo всегда сохраняет пустые строки как NULL, функция формирует условие в зависимости от значения либо в виде = 'value', либо IS NULL.

podvigLink

Расшифровка параметра шаблона «подвиг» (сведений с сайта ОБД МО «Подвиг народа»).

text = tools.podvigLink( str, imagesBase )
  • str — значение параметра «подвиг» (см. описание шаблона {{ Персона }} )
  • imageBase — признак использования нестандартного URL для изображений (используется в шаблоне {{ Представление }} )

Функция возвращает текстовую строку для включения в выходной текст. Раньше вторым параметром возвращался признак того, что ссылка на сайт ОБД МО указывает не на страницу награждения, а на страницу картотеки (теперь его всегда нет!)

local tools = {}

----------------------------------------------------------------------- |errorMsg|
local function enumeratePara( para )
	local res = ''
	local maxi = 0
	for i, v in ipairs( para ) do
		res = res .. ' | ' .. v
		maxi = i
	end
	for i, v in pairs( para ) do
		if not tonumber( i ) or tonumber( i ) > maxi then
			res = res .. ' | ' .. i .. ' = ' .. v
		end
	end
	return res
end

function tools.errorMsg( tpt, errorTxt, errorAdvice )
	if errorAdvice then
		errorAdvice = '<span class="nkvd-error-advice">' .. errorAdvice .. '. </span>'
	else
		errorAdvice = ''
	end
	return '<div class="nkvd-error"><span class="nkvd-error-tpt">{{ '
		.. '[[Шаблон:' .. tpt .. '|' .. tpt .. ']]' -- вместо .. Frame:getParent():getTitle()
		.. enumeratePara( mw.getCurrentFrame():getParent().args )
		.. ' }}</span><span class="nkvd-error-diag">'
		.. errorTxt .. '. </span>' .. errorAdvice .. '</div>'
		.. '[[Категория:Страницы с ошибками вызова шаблона «' .. tpt  .. '»]]'
end

---------------------------------------------------------------------- |checkargs|
function tools.checkargs( args, names )
    local res = {}
    local hasArg
    for k, v in pairs( args ) do
        hasArg = true
        v = mw.text.trim(v)
        if not names[k] then
            return nil, k
        elseif v == '' then
            if names[k] ~= true then
                res[k] = names[k]
            end
        else
            res[k] = v
        end
    end
    for k, v in pairs( names ) do
        if not res[k] then
            if v ~= true then
                res[k] = v
            end
        end
    end
    return res, hasArg
end

---------------------------------------------------------------------- |parseDate|
function tools.parseDate( indate, border )
	border = border or 1880
	if indate == '' then
		return ''
	end
	if string.match( indate, '[^%d%-%./ ]' ) then
		return nil
	end
	local a = mw.text.split( indate, '[%-%./ ]' )
	local f, d, m, y, dn, mn, yn
	if #a == 1 then
		f = #a[1] .. '--'
	elseif #a == 2 then
		f = #a[1] .. #a[2] .. '-'
	elseif #a == 3 then
		f = #a[1] .. #a[2] .. #a[3]
	else
		return nil
	end
	if f == '4--' then
		y = a[1]
	elseif f == '022' or f == '024' then
		m = a[2]; y = a[3]
	elseif f == '22-' or f == '24-' then
		m = a[1]; y = a[2]
	elseif f == '42-' or f == '420' then
		y = a[1]; m = a[2]
	elseif f == '224' or f == '222' then
		d = a[1]; m = a[2]; y = a[3]
	elseif f == '422' then
		y = a[1]; m = a[2]; d = a[3]
	else
		return nil
	end
	yn = tonumber( y )
	if #y == 2 then
		yn = yn + 1800
		if yn < border then
			yn = yn + 100
			y = '19' .. y
		else
			y = '18' .. y
		end
	end
	mn = tonumber( m or -1 )
	dn = tonumber( d or -1 )
	if dn == 0 or dn > 31 or mn == 0 or mn > 12 then
		return nil
	end
	--TODO: Не хватает честной проверки числа в зависимости от месяца
	return table.concat( { y, m, d }, '-' ), y, m, d
end

-------------------------------------------------------------------- |reparseDate|
function tools.reparseDate( value )
	if #value == 10 then
		return string.sub( value, 9, 10 ) .. '.'
			.. string.sub( value, 6, 7 ) .. '.'
			.. string.sub( value, 1, 4 )
	elseif #value == 7 then
		return string.sub( value, 6, 7 ) .. '.'
			.. string.sub( value, 1, 4 )
	elseif #value == 4 then
		return  string.sub( value, 1, 4 )
	end
	return '—'

end

----------------------------------------------------------------------- |textDate|
local mes = {
	i = { 'январь', 'февраль',  'март',   'апрель',  'май',  'июнь',  'июль',  'август',   'сентябрь',  'октябрь',  'ноябрь',  'декабрь', 'год'  },
	g = { 'января', 'февраля',  'марта',  'апреля',  'мая',  'июня',  'июля',  'августа',  'сентября',  'октября',  'ноября',  'декабря', 'года' },
}
function tools.textDate( value, p )
	p = p or 'i'
	if #value == 10 then
		return tonumber( string.sub( value, 9, 10 ) ) .. ' '
			.. mes.g[tonumber( string.sub( value, 6, 7 ) )] .. ' '
			.. string.sub( value, 1, 4 ) .. ' года'
	elseif #value == 7 then
		return mes[p][tonumber( string.sub( value, 6, 7 ) )] .. ' '
			.. string.sub( value, 1, 4 ) .. ' года'
	elseif #value == 4 then
		return  value .. ' ' ..  mes[p][13]
	end
	return '—'

end

------------------------------------------------------------------------- |phrase|
function tools.phrase (text)
	text = mw.text.trim( text )
	if text == '' then
		return ''
	end
	text = mw.ustring.upper( mw.ustring.sub( text, 1, 1) ) .. mw.ustring.sub( text, 2, -1 )
	local z = mw.ustring.sub( text, -1, -1 )
	if z ~= '.' and z ~= '!' and z ~= '?' then
		return text .. '.'
	end
	return text
end

----------------------------------------------------------------------- |noPhrase|
function tools.noPhrase (text)
	text = mw.text.trim( text )
	text = mw.ustring.lower( mw.ustring.sub( text, 1, 1) ) .. mw.ustring.sub( text, 2, -1 )
	if mw.ustring.sub( text, -1, -1 ) == '.'  then
		return mw.ustring.sub( text, 1, -2 )
	end
	return text
end

----------------------------------------------------------------------------- |db|
function tools.db( base, elem, field )
	local el = base[elem]
	if not el then
		return nil
	end
	if type(el) == 'table' and el.redirect then
		return tools.db( base, el.redirect, field )
	elseif field then
		return el[field]
	else
		return el
	end
end

------------------------------------------------------------------- |commonParams|
function tools.commonParams( addendum, reference, source )
	if ( addendum or '' ) ~= '' then
		addendum = ' <span class="nkvd-addendum">('
			.. tools.noPhrase( addendum )  .. ')</span>'
	else
		addendum = ''
	end
	if ( reference or '' ) ~= '' or ( source or '' ) ~= '' then
		local refTools = require( 'Module:RefTools' )
		reference = refTools.makeRef( reference )
		source = refTools.makeRef( tools.formatIfUrl( 'what', source ), true )
	else
		reference = ''
		source = ''
	end
	return addendum .. reference .. source
end

-------------------------------------------------------------------- |formatIfUrl|
function tools.formatIfUrl( whatwherefrom, txt )
	if not txt then
		return
	end
	if string.sub( txt, 1, 7 ) ~= 'http://'
			and string.sub( txt, 1, 8 ) ~= 'https://'
			and string.sub( txt, 1, 2 ) ~= '//' then
		return txt, true
	end
	if string.find( txt, ' ' ) then
		return txt, true
	end
	return require( 'Модуль:Сайт' ).link( whatwherefrom, txt )
end

------------------------------------------------------------------------ |segment|
function tools.segment( s )
	if ( s or '' ) ~= '' then
		return '<i>[' .. tostring( mw.uri.fullUrl( 'НКВД:Выборка', { class = 'segment', value = s } ) )
			.. ' ' .. s .. ']</i>'
	end
end

--------------------------------------------------------------------------- |name|
function tools.name( name, idx )
	local root
	if not idx then
		root, idx = string.match( name, '^(.+) (%([IVX%-]+%))$' )
		if not root then
			return name
		end
	else
		root = name
	end

	if idx == '' then
		return root
	else
		return root .. ' <span class="nkvd-idx">' .. idx .. '</span>'
	end
end

---------------------------------------------------------------------- |splitName|
function tools.splitName( Name, redlink )
	local name = Name
	local l, f, m, d
	local warn = {} -- мягкие предупреждения начинаются с пробела
	if string.find( name, '  ', 1, true ) then
		warn[#warn+1] = 'В имени персоны нельзя ставить несколько пробелов подряд'
		name = string.gsub( name, '  +', ' ' )
	end
	name = string.gsub( name, '%.%.%.([^%.])', '#\1' )
	name = string.gsub( name, '%.%.%.$', '#' )
	if string.match( name .. ' ', '[,#%.][^ ]' ) then
		warn[#warn+1] = 'После запятой, точки и многоточия пробелы обязательны'
		name = string.gsub( name, '([,#%.])([^ ])', '%1 %2' )
	end

	local tmp = string.find( name, ' (', 1, true )
	if tmp then
		name, d = string.sub( name, 1, tmp-1 ), string.sub( name, tmp+1, -1 )
		if not string.match( d, '^%([IVX]+%)$' ) and ( not redlink or d ~= '(*)' ) then
			return nil, 'Номер тезки должен записываться в скобках римскими цифрами'
		end
	end
	tmp = string.find( name .. ' ', ', ', 1, true )
	if tmp then
		l, f = string.sub( name, 1, tmp-1 ), string.sub( name, tmp+2, -1 )
	else
		l, f = name, ''
		if string.find( l, ' ', 1, true ) then
			warn[#warn+1] = ' Фамилия состоит из нескольких слов. Если это действительно так,'
				.. ' поставьте после нее запятую, чтобы избавиться от этого предупреждения'
		end
	end
	if string.sub( l, 1, 1 ) == '-' then
		warn[#warn+1] = 'Вместо минуса спереди используйте шаблон «персона*»'
	end
	if mw.ustring.match( f, '[а-я][а-я]%.$' ) then
		warn[#warn+1] = 'Вместо точки после ФИО используйте шаблон «персона?»'
	end
	f = string.gsub( f, '[#%.]', '' )
	if f ~= '' then
		tmp = string.find( f, ' ', 1, true )
		if tmp then
			f, m = string.sub( f, 1, tmp-1), string.sub( f, tmp+1, -1 )
		end
	end
	name = l
	m = m or ''
	if f ~= '' or m ~= '' then
		name = name .. ','
		if f == '' then
			name = name .. ' ...'
		elseif mw.ustring.len (f) == 1 then
			name = name .. ' ' .. f .. '.'
		else
			name = name .. ' ' .. f
		end
		if m ~= '' then
			name = name .. ' ' .. m
		end
		if mw.ustring.len (m) == 1 then
			name = name .. '.'
		end
	end
	if d then
		tmp = name .. ' ' .. d
	else
		tmp = name
	end
	if tmp ~= Name and #warn == 0 then
		warn[#warn+1] = ' Эталонная форма записи этого имени — «' .. tmp
			.. '». Вы уверены, что написали правильно?'
	end

	return  l, f, m, d, warn, name
end

-------------------------------------------------------------------- |cargoString|
function tools.cargoString( s )
	if ( s or '' ) == '' then
		return ' IS NULL'
	end
	return '="' .. s .. '"'
end

--------------------------------------------------------------------- |podvigLink|
function tools.podvigLink( str, imagesBase )
	if (str or '') == '' or string.sub(str, 1, 1) == '[' then
		return str
	end
	local pods = mw.text.split( str, '[%s]*,[%s]*' )
	local tabtext = {
		['+'] = {2, ', имеется наградной лист', },
		['-'] = {0, ', наградной лист отсутствует', },
		['/'] = {1, ', имеется только «описание подвига»', },
		['%'] = {1, ', имеется ссылка только на «описание подвига»', },
		['' ] = {2, '', },
	}
	local images = mw.site.server .. '/images'
	local imagesP = mw.site.server .. '/images/obdmo/saved'
	local imagesB = 'http://localhome.raczynski.ru/tools/podvig/ishow.php?l='

	local res = {}
	local x, y, tmp, ico
	local linkStyle, linkFull -- Style - 2/1/0 - картотека/представление/награждение, full - 0/1 - пустой/красим
	for _, podvig in ipairs( pods ) do
		if podvig == '' then
		elseif string.sub( podvig, 1, 1 ) == '/' then
			x = mw.text.split( podvig, '[%s]+' )
			y = {}
			if #x < 2 then
				res[#res+1] = '<i class="error fa fa-question"></i>'
			else
				for i = 2, #x do
					if imagesBase then
						tmp = imagesB .. x[1] .. '&shownumber=' .. x[i] .. '&noC=1'
						ico = ''
					else
						if string.sub( x[i], -1, -1 ) == '-' then
							tmp = string.sub( '00000000' .. string.sub( x[i], 1, -2 ), -8, -1 ) .. '_1'
							ico = '-o'
						else
							tmp = string.sub( '00000000'..x[i], -8, -1 )
							ico = ''
						end
						tmp = imagesP .. x[1] .. '/' .. tmp .. '.jpg'
					end
					y[#y+1] =  '[' .. tmp
						.. ' <i class="fa fa-file-text' .. ico
						.. '"  style="color:gray; font-size:82%;" title="Сохраненные материалы"></i>]'
				end
				res[#res+1] = '<span class=nkvd-hide-inline> ' .. table.concat( y, ' ' ) .. '</span>'
			end
		else
			x, y = string.match( podvig, '^(%d+) *([%+%-%*%%/#!]*)$' )
			if not x then
				linkStyle = -1
			else
				if y == '#' then
					linkStyle, linkFull = 2, 0
					y = ' в картотеке награждений'
				elseif y == '!' then
					linkStyle, linkFull = 3, 0
					y = ''
				else
					linkFull, linkStyle = string.gsub( y, '%*', '' )
					y = tabtext[linkFull]
					if not y then
						linkStyle = -1
					else
						linkFull = y[1]
						y = y[2]
					end
				end
			end
			if linkStyle == -1 then
				res[#res+1] = '<i class="error fa fa-question"></i>'
			else
				if linkFull == 0 then
					linkFull = '-o'
				elseif linkFull == 1 then
					linkFull = '-half-o'
				else
					linkFull = ''
				end
				tmp = ''
				if linkStyle ~= 2 then
					if linkStyle == 0 then
						tmp = 'nagrazhdenie'
					elseif linkStyle == 3 then
						tmp = 'yubileinaya_kartoteka'
					else
						tmp = 'predstavlenie'
					end
					res[#res+1] = ' &nbsp;[https://pamyat-naroda.ru/heroes/podvig-chelovek_' .. tmp
						.. x .. '/ <i class="fa fa-star' .. linkFull
						.. '" style="color:#D33738; font-size:82%;" title="Информация о награждении на сайте «Память народа»'
						.. y ..'"></i>] '
						.. '[http://podvignaroda.ru/#?id='
						.. x .. ' <i class="fa fa-star' .. linkFull
						.. '" style="color:gray; font-size:82%;" title="Информация о награждении на сайте «Подвиг народа»'
						.. y ..'"></i>]'
						.. '<span class=nkvd-hide-inline> [http://localhome.raczynski.ru/tools/podvig?n=' .. x
						.. '&noC=1 <span style="color:#ffdd75" title="Sorry, internal use only">&nabla;</span>]</span>'
--					linkStyle = false
				else
					res[#res+1] = ' &nbsp;[http://podvignaroda.ru/#?id='
						.. x .. '  <i class="fa fa-folder-o'
						.. '" style="color:gray; font-size:82%;" title="Информация о награждении на сайте «Подвиг народа»'
						.. y ..'"></i>]'
						.. '<span class=nkvd-hide-inline> [http://localhome.raczynski.ru/tools/podvig?n=' .. x
						.. '&noC=1 <span style="color:#ffdd75" title="Sorry, internal use only">&nabla;</span>]</span>'
--					linkStyle = true
				end
			end
		end
	end

	return table.concat( res, ' &nbsp; ' ) -- , linkStyle
end



--=================================================================== |проверять!|
-- функции, по которым остались сомнения в использовании

tools.dateLength = {[''] = 10, ['1'] = 10, ['2'] = 7, ['3'] = 4}
function tools.ReparseDate ( frame )
	return tools.reparseDate(
		string.sub(frame.args[1], 1, tools.dateLength[frame.args[2] or ''] ) )
end

--==================================================================== |на выброс|
-- неиспользуемые функции
--[====[
function tools.flip( array, value )
    local res = {}
    for k, v in pairs( array ) do
        res[v] = value or k
    end
    return res
end

function tools.args( args )
	local res, x = {}
	for k,v in pairs( args ) do
		x = mw.text.trim(v)
		if x ~= '' then
			res[k] = x
		end
	end
	if x then
		res['___HAS_ARG___'] = true
	end
	return res
end

function tools.cq( tables, fields, args )
	return mw.ext.cargo.query( tables, fields, args )
end
--]====]


return tools