--[[
Модуль предназначен для форматирования библиографических ссылок на книжные издания
]]
local p = {}
--[[
Список параметров
Имена параметров должны быть в нижнем регистре.
]]
p.config = {
param_autor = 'автор',
param_part_link = 'ссылка часть',
param_part_title = 'часть',
param_part_material = 'часть материал',
param_part_alt = 'часть оригинал',
param_part_ext = 'часть сведения',
param_part_resp = 'часть ответственный',
param_wikisource = 'викитека',
param_url = 'ссылка',
param_title = {'название', 'заглавие'},
param_material = 'материал',
param_alt_title = 'оригинал',
param_ext_title = 'сведения',
param_responsible = 'ответственный',
param_edition = 'издание',
param_alt_edition = 'издание оригинал',
param_edition_resp = 'издание ответственный',
param_edition_info = 'об издании',
param_edition_info_resp = 'об издании ответственный',
param_place = {'город', 'место'},
param_publisher = 'издательство',
param_year = 'год',
param_phys = 'объем',
param_ext_phys = 'объем доп',
param_size = 'размеры',
param_addition = 'комплект',
param_volumes = 'томов',
param_volume = {'том как есть', ru = 'том', en = 'volume', de = 'band'},
param_volume_subtitle = 'подзаголовок тома',
param_number = 'номер',
param_issue = {ru = 'выпуск', en = 'issue', de = 'heft'},
param_issue_subtitle = 'подзаголовок выпуска',
param_columns = {ru = 'столбцы', en = 'columns', de = 'kolonnen'},
param_pages = {'страницы как есть', ru = 'страницы', en = 'pages', de = 'seite'},
param_all_pages = {'страниц как есть', ru ='страниц', en = 'allpages', de = 'alleseiten'},
param_series = 'серия',
param_alt_series = 'серия оригинал',
param_ext_series = 'серия сведения',
param_resp_series = 'серия ответственный',
param_series_issn = 'серия issn',
param_series_issue = 'серия выпуск',
param_comment = 'примечание',
param_copies = 'тираж',
param_issn = 'issn',
param_isbn = 'isbn',
param_doi = 'doi'
}
-- Подстрочная библиографическая ссылка ГОСТ 7.1—2003
function p._ref(args)
local param_handlers = {} -- таблица обработчиков параметров
-- формат значения
local function format_string(str, fmt)
str = mw.ustring.gsub( str, "%%", "%%%%" ); -- маркируем знак процента
return mw.ustring.gsub(fmt, '$1', str); -- заменяем $1
end
-- получить параметр по внутреннему имени и префиксу
local function getparam (x, suffix)
local param_names = p.config['param_' .. x];
if param_names == nil then
return '';
end
if suffix == nil then
suffix = '';
end
local formater = param_handlers[x];
local function readparam(key, name)
local param_name = name .. suffix;
local value = args[param_name] or '';
-- mw.log('readparam(\'' .. key .. '\', \'' .. param_name .. '\') = \'' .. value .. '\'')
if formater ~= nil then
if type(formater) == 'function' then
value = formater(value, suffix, key)
elseif type(formater) == 'table' and value ~= '' then
local fmt = formater[key] or '';
if fmt ~= '' then
value = format_string(value, fmt)
end
elseif type(formater) == 'string' and value ~= '' then
value = format_string(value, formater)
end
end
return value;
end
local result ='';
if type(param_names) == 'table' then
for key, param_name in pairs(param_names) do
result = readparam(key, param_name);
if result ~= '' then
break
end
end
elseif type(param_names) == 'string' then
result = readparam('', param_names);
end;
return result;
end
-- обход блоков вглубь с объединением результатов в строку
local function process(f, level, suffix)
-- обработка повторяющихся блоков
local function iterate(f)
local result = '';
if f == nil then
return result;
end
local nextlevel = level;
if f.block ~= nil and f.beforenext ~= nil then
nextlevel = nextlevel +1;
end
local i = 1;
while true do
local sfx = suffix;
if i > 1 then
if level > 0 then
sfx = sfx .. '_';
end
sfx = sfx .. tostring(i);
end
local str = process(f, nextlevel, sfx);
if str == nil or str == '' then
break; -- пустой блок
end
if f.vformat ~= nil and f.vformat ~= '' then
str = format_string(str, f.vformat);
end
if f.beforenext == nil then
-- неповторяющийся блок
result = str;
break;
else
if result ~= '' and f.beforenext ~= nil and f.beforenext ~= '' then
result = result .. f.beforenext; -- добавляем разделитель до
end
result = result .. str;
end
i = i + 1;
end
return result;
end
local result = '';
if level == nil then
level = 0;
end
if suffix == nil then
suffix = ''; -- префикс параметра по умолчанию
end
if f.block ~= nil and type(f.block) == 'table' then
local after = '';
for i=1, #f.block do
local str = iterate(f.block[i]);
if str ~= '' then
if result ~= '' then -- не первый непустой блок
result = result .. after; -- разделитель после, указанный в предыдущем блоке
if f.block[i].before ~= nil and f.block[i].before ~= '' then
result = result .. f.block[i].before;
end
end
result = result .. str;
after = f.block[i].after or '';
end
end
elseif f.param ~= nil and type(f.param) == 'string' then
result = getparam(f.param, suffix) or '';
end
return result;
end
--[[
Далее идут обработчики значений
Функция обработчика принимает три параметра:
1. внутреннее имя параметра из p.config без 'param_'
2. префикс (название блока, если параметр есть в разных блоках)
3. суффикс (порядковое значение, если имя тоже)
]]
-- Автор
param_handlers['autor'] = function (x, suffix)
if x == '' then
return x;
end
x, i = mw.ustring.gsub( x, '^(%[*)(.-[^%.%]])(%]*)%.?$', '%1%2%3.'); -- добавляем точку если её нет
mw.logObject(i, 'i');
return '<i>' .. x .. '</i>';
end
-- Название части
param_handlers['part_title'] = function (x, suffix)
if x == '' then
return x;
end
local l = getparam('part_link', suffix) or ''
if l ~= '' then
return '[' .. l .. ' ' .. x .. ']'
else
return x
end
end
-- Основное заглавие
param_handlers['title'] = function (x, suffix)
if x == '' then
return x;
end
x = mw.ustring.gsub( x, '^(.-)%.$', '%1'); -- всегда убираем точку в конце названия
local ws = getparam('wikisource', suffix) or ''
if ws ~= '' then
x = '[[:s:' .. ws .. '|' .. x .. ']]';
else
local l = getparam('url', suffix) or ''
if l ~= '' then
x = '[' .. l .. ' ' .. x .. ']';
end
end
return x
end
-- Общее обозначение материала
function format_material(x, suffix)
if x == '' then
return x;
end
local materialtype_ru = {
['видеозапись']=1, ['звукозапись']=2, ['изоматериал']=3, ['карты']=4,
['комплект']=5, ['кинофильм']=6, ['микроформа']=7, ['мультимедиа']=8,
['ноты']=9, ['предмет']=10, ['рукопись']=11, ['текст']=12,
['шрифт Брайля']=13, ['электронный ресурс']=14
}
local materialtype_en = {
['videorecording']=1, ['sound recording']=2, ['graphic']=3,
['cartographic material']=4, ['kit']=5, ['motion picture']=6, ['microform']=7,
['multimedia']=8, ['music']=9, ['object']=10, ['manuscript']=11, ['text']=12,
['braille']=13, ['electronic resource']=14
}
local lmt = mw.ustring.lower(x);
if (materialtype_ru[lmt] ~= nil or materialtype_en[lmt] ~= nil) then
return '[' .. x .. ']';
else
return ''; -- игнорируем
end
end
param_handlers['material'] = format_material;
param_handlers['part_material'] = format_material;
-- формат места издание
param_handlers['place'] = function (x, suffix)
if x == '' then
return x;
end
local knownPlaces = { ['L.'] = 'London', ['N. Y.'] = 'New York', ['P.'] = 'Paris', ['Б.'] = 'Баку',
['Б. м.'] = 'без указания места', ['Ер.'] = 'Ереван', ['Иер.'] = 'Иерусалим', ['К.'] = 'Киев',
['Каз.'] = 'Казань', ['Л.'] = 'Ленинград', ['М.'] = 'Москва', ['Мн.'] = 'Минск',
['Н. Н.'] = 'Нижний Новгород', ['Н. Новгород'] = 'Нижний Новгород', ['Пг.'] = 'Петроград',
['Ростов н/Д'] = 'Ростов-на-Дону', ['СПб.'] = 'Санкт-Петербург', ['Тб.'] = 'Тбилиси',
['Тф.'] = 'Тифлис', ['Яр.'] = 'Ярославль'
}
local kp = knownPlaces[x];
if kp ~= nil then
if kp == 'без указания места' then
x = '[' .. x .. ']';
end
return '<img style="border-bottom:1px dotted gray; cursor:default;" title="'.. kp .. '">' .. x .. '</img>';
else
return x;
end
end
param_handlers['volumes'] = '$1 т.';
param_handlers['number'] = '№ $1';
param_handlers['volume'] = { '', ru = 'Т. $1', en = 'Vol. $1', de = 'B. $1' };
param_handlers['issue'] = { ru = 'Вып. $1', en = 'Iss. $1', de = 'H. $1' };
param_handlers['columns'] = { ru = '(стб. $1)', en = '(col. $1)', de = '(Kol. $1)' };
param_handlers['all_pages'] = { '', ru = '$1 с.', en = '$1 p.', de = '$1 s.' };
param_handlers['pages'] = function (x, suffix, name)
if x == '' then
return x;
end
local fmts = { '', ru = 'С. $1', en = 'P. $1', de = 'S. $1' }
local fmt = fmts[name] or '';
if fmt ~= '' then
local col = getparam('columns', suffix) or '';
if col ~= '' then
x = '['.. x .. '] ' .. col;
end
x = format_string(x, fmt)
end
return x;
end
param_handlers['phys'] = function (x, suffix, name)
if x == '' then
x = getparam('volumes', prefix, suffix) or '';
local ap = getparam('all_pages', suffix) or '';
if ap ~= '' then
if x ~= '' then
x = x .. ', ' .. ap;
else
x = ap;
end
end
end
return x
end
param_handlers['copies'] = '$1 экз.';
param_handlers['isbn'] = 'ISBN $1';
param_handlers['series_issn'] = 'ISSN $1';
param_handlers['issn'] = 'ISSN $1';
param_handlers['doi'] = 'DOI $1';
local sep = '. — ' -- точка и тире
-- Область заглавия и сведений об ответственности
local title_area = {
{ param = 'title' }, -- Основное заглавие
{ param = 'material', before = ' ' }, -- Общее обозначение материала
{ param = 'alt_title', before = ' = ', beforenext = ' = ' }, -- Параллельное заглавие
{ param = 'ext_title', before = ' : ', beforenext = ' : ' }, -- Сведения, относящиеся к заглавию
{ param = 'responsible', before = ' / ', beforenext = '; ' } -- Cведения об ответственности
}
-- Область издания
local edition_area = {
{ param = 'edition' }, -- Сведения об издании
{ param = 'alt_edition', before = ' = ' }, -- Параллельные сведения об издании
{ param = 'edition_resp', before = ' / ', beforenext = '; ' }, -- Сведения об ответственности, относящиеся к изданию
{ param = 'edition_info', before = ', ', beforenext = '; ' }, -- Дополнительные сведения об издании
{ param = 'edition_info_resp', before = ' / ', beforenext = '; ' } -- Сведения об ответственности, относящиеся к дополнительным сведениям об издании
}
-- Область нумерации
local number_area = {
{ param = 'volume' }, -- Том
{ param = 'issue', before =', ' }, -- Номер выпуска
{ param = 'number', before =', ' }, -- Номер
{ param = 'volume_subtitle', before =' : ' } -- Частное заглавие тома или выпуска
}
-- Сведения о местоположении объекта ссылки в документе (если ссылка на часть документа);
local ref_area = {
{ block = number_area, name='number_area' }, -- Область нумерации
{ param = 'pages', before = sep, beforenext = sep } -- Номера страниц и столбцов в цитируемом источнике
}
-- Область выходных данных
local output_data_area = {
{ param = 'place', beforenext= ' ; ' }, -- Место издания, распространения
{ param = 'publisher', before = ' : ', beforenext = ' : ' }, -- Имя (наименование) издателя, распространителя и т. п.
-- Сведения о функции издателя, распространителя и т. п. пропущены
{ param = 'year', before = ', ' }, -- Дата издания, распространения и т. п.
-- Место изготовления, имя изготовителя и дата изготовления пропущены
{ block = ref_area, before = sep, beforenext = ' ; ' } -- Сведения о местоположении объекта ссылки в документе (если ссылка на часть документа);
}
-- Сведения об объеме документа (если ссылка на весь документ)
local phys_area = {
{ param = 'phys' }, -- Специфическое обозначение материала и объем
{ param = 'ext_phys', before = ' : ' }, -- Другие сведения о физической характеристике
{ param = 'size', before = ' ; ' }, -- Размеры
{ param = 'addition', before = ' + ', beforenext = ' + ' } -- Сведения о сопроводительном материале
}
-- Область серии
local series_area = {
{ param = 'series' }, -- Основное заглавие серии или подсерии
{ param = 'alt_series', before = ' = ', beforenext = ' = ' }, -- Параллельное заглавие серии или подсерии
{ param = 'ext_series', before = ' : ', beforenext = ' : ' }, -- Сведения, относящиеся к заглавию серии или подсерии
{ param = 'resp_series', before = ' / ', beforenext = '; ' }, -- Сведения об ответственности, относящиеся к серии или подсерии
{ param = 'series_issn', before = ' , ' }, -- Международный стандартный номер сериального издания (ISSN), присвоенный данной серии или подсерии
{ param = 'series_issue', before = ' ; ' } -- Номер выпуска серии или подсерии
}
-- Сведения об идентифицирующем документе
local document_area = {
{ block = title_area, beforenext='. ' }, -- Область заглавия и сведений об ответственности
{ block = edition_area, before = sep }, -- Область издания
{ block = output_data_area, before = sep }, -- Область выходных данных
{ block = phys_area, before = sep }, -- Сведения об объеме документа (если ссылка на весь документ)
{ block = series_area, before = sep, beforenext = ' ',
vformat = '($1)' }, -- Область серии
}
-- Сведения о составной части документа
local part_area = {
{ param = 'part_title' }, -- Заглавие части
{ param = 'part_material', before = ' ' }, -- Общее обозначение материала части
{ param = 'part_alt', before = ' = ', beforenext = ' = ' }, -- Параллельное заглавие части
{ param = 'part_ext', before = ' : ', beforenext = ' : ' }, -- Сведения, относящиеся к заглавию части
{ param = 'part_resp', before = ' / ', beforenext = '; ' } -- Cведения об ответственности части
}
-- Аналитическое библиографическое описание
local description = {
{ param = 'autor', after=' ' }, -- Автор
{ block = part_area, after=' // ', beforenext='. ' }, -- Сведения о составной части документа
{ block = document_area, after=sep }, -- Сведения об идентифицирующем документе
{ param = 'comment', after = sep, beforenext= ' — ' }, -- Область примечания
{ param = 'copies', after = sep }, -- Тираж
{ param = 'issn', after = sep }, -- Международный стандартный издания
{ param = 'isbn', after = sep, beforenext=sep }, -- Международный стандартный номер книги
{ param = 'doi' } -- Идентификатор цифрового объекта
}
-- удаление точки перед разделителем
local function removeDotBefore(s, sep)
-- разделитель без лидирующей точки
local nodotsep = mw.ustring.sub(sep, 2);
-- маскируем спецсимволы в разделителе
local esep = mw.ustring.gsub( sep, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" );
-- убираем точку в разделителе, если перед ним восклицательный, вопросительный знак или многоточие
local result = mw.ustring.gsub(s, '([!%?…]%]?%]?)'.. esep, '%1' .. nodotsep);
-- убираем точку перед разделителем
return mw.ustring.gsub(result, '%.'.. esep, sep);
end
-- добавление точки в конце
local function addDotAfter(s)
local fs = mw.ustring.gsub( s, '%b<>', ''); -- убираем теги в строке
-- проверяем есть ли в конце строки точка
if mw.ustring.match(fs, '^.-[^!%?.…]%]?%]?$' ) then
s = s .. '.';
end
return s;
end
-- добавления якоря ссылки
local function AddRef(s)
if s ~= '' then
local id = args['ref'] or '';
if id ~= '' then
local y = args['год'] or '';
local b = args['буква'] or '';
id = 'CITEREF' .. id .. y .. b;
id = ' id="' .. mw.uri.anchorEncode( id ) .. '"';
end
s = '<img class="citation"' .. id .. '>' .. s .. '</img>';
end
return s;
end
local result = process({block = description, name='description' });
result = removeDotBefore(result, sep); -- удаление лишней точки перед разделителем
result = addDotAfter(result); -- описание заканчивается точкой
result = AddRef(result);
return result;
end
function p.ref(frame)
local pframe = frame:getParent()
local args = {};
for key, value in pairs(pframe.args) do
if type(key) == 'string' and key ~= '' then
args[mw.ustring.lower(key)] = value;
end
end
return p._ref(args);
end;
return p