Модуль:CiteWeb
Для документации этого модуля может быть создана страница Модуль:CiteWeb/doc
local p = {};
require('strict');
local listRef = require('Module:Languages').list_ref;
local boxDate = require('Module:Calendar').bxDate;
local error_cats = {
['noname_param'] = 'Категория:Википедия:Cite web (некорректное использование: непустой неименованный параметр)',
['empty_title'] = 'Категория:Википедия:Cite web (некорректное использование: не указан title)',
['empty_url'] = 'Категория:Википедия:Cite web (некорректное использование: не указан url)',
['bad_archive'] = 'Категория:Википедия:Cite web (некорректное использование: параметры архивации)',
['deadlink'] = 'Категория:Википедия:Cite web (недоступные ссылки без архивной копии)',
-- ['bad_lang'] = 'Категория:Википедия:Cite web (неверный код языка)',
-- ['deadlink_old'] = 'Категория:Википедия:Cite web (устаревшие параметры мёртвых ссылок)',
['empty_lang'] = 'Категория:Википедия:Cite web (не указан язык)',
['bad_url'] = 'Категория:Википедия:Cite web (некорректный url)',
['webcitation_no'] = 'Категория:Википедия:Cite web (заменить webcitation-архив: deadlink no)',
['webcitation_yes'] = 'Категория:Википедия:Cite web (заменить webcitation-архив: deadlink yes)',
}
local errors = {
['noname_param'] = '{{error|Все параметры шаблона {{tl|cite web}} должны [[T:cite web#Неименованные_параметры|иметь имя]].}}',
['empty_title'] = '{{error|Необходимо задать параметр {{code|title{{=}}}} в шаблоне {{tl|cite web}}.}}',
['empty_url'] = '{{error|Необходимо задать параметр {{code|url{{=}}}} в шаблоне {{tl|cite web}}.}}',
['bad_archive'] = '{{error|Если в шаблоне {{tl|cite web}} задаётся параметр {{code|archive-url{{=}}}}, должен задаваться и параметр {{code|archive-date{{=}}}}, и наоборот.}}',
}
local replace_params = {
['accessdate'] = 'access-date',
['archivedate'] = 'archive-date',
['archiveurl'] = 'archive-url',
['authorlink'] = 'author-link',
['first1'] = 'first',
['last1'] = 'last',
['deadurl'] = 'deadlink',
['dead-url'] = 'deadlink',
['language'] = 'lang',
['datepublished'] = 'date',
['work'] = 'website',
}
-- проверка существования переменной. возврат её, или nil если пустая
local function is(var)
if (var == '' or var == nil) then return nil else return var end
end
-- замена устаревших аргументов на их аналоги
local function prepareArgs(args)
local bad_args = {};
local new_args = {};
for param, value in pairs(args) do
if is(replace_params[param]) and not is(args[replace_params[param]]) then
param = replace_params[param];
end
new_args[param] = value;
end
return new_args, bad_args
end
-- добавление скрытого языка
local function hiddenRef(code)
return '<span class="hidden-ref" style="display:none;"> ' .. code .. '</span>'
end
local function insertDot(str, small, insert)
if insert == false then
return
end
if small then
table.insert(str, '<small>.</small>')
else
table.insert(str, '.')
end
end
local function needDot(source_str)
if mw.ustring.find(source_str, '[.?!:…]»?$') ~= nil then
return false
else
return true
end
end
local function nowiki(text)
local frame = mw.getCurrentFrame();
return frame:callParserFunction('#tag', { 'nowiki', text })
end
local function replace(source_str, pattern, replace)
return mw.ustring.gsub(source_str, pattern, replace)
end
-- форматирование даты; в случае ошибки - возврат переданного значения без изменений
local function formatDate(strFormat, txtDateIn, params)
local txtDateOut, date, status = boxDate(txtDateIn, strFormat, params)
if status.brk then
return txtDateIn
else
return txtDateOut
end
end
-- отрисовка ошибки по коду
local function expandError(code)
return mw.getCurrentFrame():preprocess(errors[code]) .. ' '
end
-- отрисовка всех категорий по их кодам
local function expandCats(cats)
local str = {};
local frame = mw.getCurrentFrame();
for _, cat in pairs(cats) do
table.insert(str, '[[' .. error_cats[cat] .. ']]')
end
return frame:preprocess(table.concat(str))
end
-- разделение их
local function splitBySlash(string)
local args = {};
local iterator = mw.ustring.gmatch(string, "[^/]+");
for w in iterator do
table.insert(args, w)
end
return args
end
-- оборачиваем главную ссылку в span с указанным языком (может быть полезно для rtl)
local function wrapLang(link, langs)
local lang_code = 'und';
if is(langs) then
local args = splitBySlash(langs);
if #args ~= 0 then
lang_code = args[1];
end
end
return '<span lang="' .. lang_code .. '">' .. link .. '</span>'
end
-- обёртка в тег цитирования
local function wrapCite(str, args)
if is(args['ref']) then
table.insert(str, 1, '<span class="citation" id="CITEREF' .. mw.uri.anchorEncode(args['ref']) .. '">');
if is(args['date']) then
table.insert(str, 2,
'<span class="citation" id="CITEREF' ..
mw.uri.anchorEncode(args['ref'] .. formatDate('Y', args['date'])) .. '">');
table.insert(str, '</span>');
end
else
table.insert(str, 1, '<span class="citation">');
end
table.insert(str, '</span>');
end
-- генерирум список языков (аргумент - список языков через слеш)
local function refLang(lang)
local args = splitBySlash(lang);
local frame = mw.getCurrentFrame();
frame.args = args
local lang_result = listRef(frame)
local hidden = false;
if #args == 1 and args[1] == 'ru' then
hidden = true;
end
return lang_result, hidden
end
function p.render(frame)
local str = {}
local cats = {}
local pFrame = frame:getParent();
local args = mw.clone(pFrame.args);
setmetatable(args, nil);
args = prepareArgs(args);
-- Проверки
-- Проверка отсутствия неименованных параметров
if is(args[1]) or is(args[2]) or is(args[3]) or is(args[4]) or is(args[5]) or is(args[6]) then
table.insert(str, expandError('noname_param'));
table.insert(cats, 'noname_param');
end
-- Проверка корректности заполнения параметров archiveurl и archivedate
if (is(args['archive-date']) ~= nil and is(args['archive-url']) == nil) or
(is(args['archive-date']) == nil and is(args['archive-url']) ~= nil) then
table.insert(str, expandError('bad_archive'));
table.insert(cats, 'bad_archive');
end
-- Проверка устаревших параметров мёртвых ссылок
-- if is(args['dead-url']) or is(args['deadurl']) then
-- table.insert(cats, error_cats['deadlink_old'])
-- end
local urlstatus = 'live';
if args['url-status'] == 'live' or args['url-status'] == 'dead' or args['url-status'] == 'unfit' then
urlstatus = args['url-status']
elseif args['deadlink'] == 'yes' then
urlstatus = 'dead'
elseif args['deadlink'] == 'unfit' then
urlstatus = 'unfit'
end
local is_webcitation_archive = false;
if is(args['archive-url']) then
if mw.ustring.find(args['archive-url'], 'webcitation.org', 1, true) then
is_webcitation_archive = true
if urlstatus == 'dead' or urlstatus == 'unfit' then
table.insert(cats, 'webcitation_yes')
else
table.insert(cats, 'webcitation_no')
end
end
elseif urlstatus == 'dead' then
table.insert(cats, 'deadlink')
end
-- Проверка заполнения параметра url
if is(args['url']) then
if mw.ustring.find(args['url'], '^https?://', 1, false) ~= 1 and
mw.ustring.find(args['url'], '^ftp://', 1, false) ~= 1 or mw.ustring.find(args['url'], ' ', 1, true) ~= nil then
table.insert(cats, 'bad_url')
end
else
table.insert(str, expandError('empty_url'));
table.insert(cats, 'empty_url')
end
-- Проверка заполнения параметра title
if not is(args['title']) then
table.insert(str, expandError('empty_title'));
table.insert(cats, 'empty_title')
elseif not is(args['lang']) and mw.ustring.find(args['title'], '^[0-9А-яЁё«»:;,…!? %(%)%.—№%/%&%#+-]+$') == nil then
table.insert(cats, 'empty_lang')
end
-- Формирование вывода
-- Автор
if is(args['author']) or is(args['last']) then
table.insert(str, '<i>')
local author = args['author'];
if is(args['last']) then
author = args['last']
if is(args['first']) then
author = author .. ', ' .. args['first']
end
elseif not is(args['last2']) and not is(args['coauthors']) then
author = replace(author, '^(%[*)(.-[^%.%]])(%]*)$', '%1%2%3.')
end
if is(args['author-link']) then
table.insert(str, '[[' .. args['author-link'] .. '|' .. author .. "]]")
else
table.insert(str, author)
end
-- Дополнительные сведения об авторах
for i = 2, 5 do
if is(args['last' .. i]) then
local author = nowiki(';') .. ' ' .. args['last' .. i];
if is(args['first' .. i]) then
author = author .. ', ' .. args['first' .. i]
end
table.insert(str, author)
end
end
if is(args['coauthors']) then
table.insert(str, nowiki(';') .. ' ' .. replace(args['coauthors'], '^(.-)%.?$', '%1.') .. ': ')
end
table.insert(str, '</i> ')
end
-- Редактор
if is(args['editor']) then
table.insert(str, ' ' .. args['editor'] .. ': ')
end
-- URL, заголовок
local link;
local title = replace(replace(args['title'] or '', '%[', '['), '%]', ']');
local dot = needDot(title);
if (urlstatus == 'dead' or urlstatus == 'unfit') and is(args['archive-url']) and not is_webcitation_archive then
link = '[' .. (args['archive-url'] or '') .. ' ' .. title .. ']'
elseif urlstatus == 'unfit' then
link = title
else
link = '[' .. (args['url'] or '') .. ' ' .. title .. ']'
end
table.insert(str, wrapLang(link, args['lang']))
-- Подзаголовок
if is(args['subtitle']) then
insertDot(str, false, dot)
table.insert(str, ' <small>' .. args['subtitle'] .. '</small>')
dot = needDot(args['subtitle']);
end
-- Отображение названия языка источника
local langs;
local hidden = false;
if is(args['lang']) then
langs, hidden = refLang(args['lang']);
else
langs = frame:expandTemplate { title = 'ref-und' };
hidden = true;
end
if hidden == true then
langs = hiddenRef(langs);
else
dot = true;
end
table.insert(str, langs)
-- Формат источника
if is(args['format']) then
dot = true;
table.insert(str, ' (' .. args['format'] .. ')')
end
-- Пометка о недоступности
if (urlstatus == 'dead' or urlstatus == 'unfit') and (not is(args['archive-url']) or is_webcitation_archive) then
dot = true;
table.insert(str,
frame:expandTemplate { title = 'ref-info',
args = { 'недоступная ссылка — [//web.archive.org/web/*/' ..
args['url'] .. ' <i>история</i>]' } })
end
-- Название сайта или проекта
if is(args['website']) then
insertDot(str, is(args['subtitle']), dot)
dot = true;
table.insert(str, ' <i>' .. args['website'] .. '</i>')
end
-- Страницы
if is(args['pages']) then
dot = true;
table.insert(str, ' ' .. args['pages'])
end
-- Страница
if is(args['page']) then
dot = true;
table.insert(str, ' ' .. args['page'])
end
-- Место, издательство
if is(args['publisher']) then
insertDot(str, is(args['subtitle']), dot)
dot = true;
table.insert(str, ' ');
if is(args['location']) then
table.insert(str, args['location'] .. ': ')
end
table.insert(str, args['publisher'])
end
-- Дата
if is(args['date']) then
dot = true;
table.insert(str, ' (' .. formatDate('j xg Y', args['date']) .. ')')
elseif is(args['year']) then
dot = true;
if is(args['month']) then
table.insert(str, ' (' .. args['month'] .. ' ' .. args['year'] .. ')')
else
table.insert(str, ' (' .. args['year'] .. ')')
end
end
-- Точка
insertDot(str, is(args['subtitle']), dot)
-- DOI
if is(args['doi']) then
table.insert(str,
' [[Идентификатор цифрового объекта|doi]]:[http://dx.doi.org/' ..
args['doi'] .. ' ' .. args['doi'] .. '].')
end
-- Описание
if is(args['description']) then
table.insert(str, ' — ' .. args['description'])
insertDot(str, true, needDot(args['description']))
end
-- Цитата
if is(args['quote']) then
table.insert(str, ' — «' .. args['quote'] .. '»')
insertDot(str, true, needDot(args['quote']))
end
-- Дата обращения
if is(args['access-date']) then
table.insert(str, ' <small>Дата обращения: ' ..
formatDate('j xg Y', args['access-date']) .. '.</small>')
end
-- Дата архивирования
if is(args['archive-date']) and is(args['archive-url']) then
if urlstatus == 'live' or is_webcitation_archive then
table.insert(str,
' <small>[' ..
args['archive-url'] ..
' Архивировано] ' ..
formatDate('j xg Y', args['archive-date']) .. ' года.</small>')
elseif urlstatus == 'unfit' then
table.insert(str,
' <small>Архивировано ' ..
formatDate('j xg Y', args['archive-date']) .. ' года.</small>')
else
table.insert(str,
' <small>Архивировано из [' ..
args['url'] ..
' оригинала] ' ..
formatDate('j xg Y', args['archive-date']) .. ' года.</small>')
end
end
wrapCite(str, args);
if #cats ~= 0 and mw.title.getCurrentTitle():inNamespace(0) then
table.insert(str, expandCats(cats));
end
return table.concat(str)
end
return p;