Модул:Sources
| Овај Луа модул се користи на веома великом броју страница, тако да ће промене на њему бити широко примећене. Молимо да било какве измене тестирате на подстраницама модула /песак или /тестови. Размислите и о постављању расправе о променама које намеравате да унесете на страници за разговор пре њиховог примењивања. |
| Овај модул је предмет заштите страница. То је веома коришћен модул у употреби огромног броја страница или се супституише веома често. Због вандализма или грешака које би утицале на много страница или тривијалног уређивања које би могло да изазове проблеме на серверима, модул је заштићен од уређивања. |
| Пре било каквог мењања овог шаблона, молимо да прво истестирате своје промене на подстраници /игралиште и упоредите их на подстраници /тестови. Тестиране промене онда треба да се унесу у једној измени у овај шаблон. |
Начин рада
Овај модул генерише текст коришћен у фуснотама изведеним са ставки Википодатака.
Функције
Спољашње
Спољашње функције прихватају објекте типа фрејма и предвиђени су за позивање из других модула или преко функције рашчлањивања {{#invoke:}}.
Директно позивање на функције модула у чланцима је крајње непожељно! У ту сврху користите одговарајуће шаблоне.
p.renderSource(frame)
Враћа текст вики-везе до одређеног извора ради уметања у референцу или библиографију. Погледајте шаблоне {{source}} и {{извор}} који користе ову функцију. Подржава следеће аргументе:
frame.args[1]— анонимни аргумент који одређује идентификатор објекта на Википодацима помоћу којег би веза требало да се генерише. На пример, Q20750516.frame.args['ref']— поставља ознаку ref, која се касније може користити у шаблонима попут {{sfn}}.frame.args['ref-year']— поставља ознаку ref-year, која се користи слично као на ознаци ref.frame.args['part']— додатни аргумент за разјашњење дела извора на који се позива (на пример, поглавље у књизи).frame.args['parturl']— веза за део који је описан претходним аргументом.frame.args['pages']— одређене странице у извору на који се референца успоставља.frame.args['url']— омогућава изричито одређење која веза ће требати да се постави на извор.frame.args['volume']— омогућава изричито назначавање тома извора на који се референца односи.frame.args['issue']— омогућава изричито назначавање издања извора на који се референца односи.
Већина аргумената происходи из utils.copyArgsToSnaks. Сам преносни оквир се налази у p.currentFrame за даљу употребу и на основу аргумената прослеђених функцији artificialSnaks формира вештачки делови, која повезује на извор поменут у frame.args[1], кроз својства Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). и Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value).. Подаци се затим преносе у renderReferenceImpl за даљу обраду.
p.renderReference(frame, currentEntity, reference)
Враћа форматиран вики текст референце датом извору. Подржава исте аргументе као и p.renderSource, а поред тога ref и ref-year. Погледајте шаблоне {{source-ref}} и {{ВП-фуснота}}, користећи ову функцију. Такође се користи у Модул:Wikidata да бисте приказали везе наведене поред упита са Википодатака. Ако недостају currentEntity и reference, ствара сопствени снек помоћу функције artificialSnaks, након чега се прослеђује у renderReferenceImpl. Ако је вики-текст за референцу успешно генерисан, обвијен је ознаком <ref> уз помоћ frame:extensionTag, при чему назив референце настаје хеширањем прослеђеног вики-текста у mw.hash.hashValue. Чланци са таквим фуснотама стављају се у Категорија:Википедија:Чланци са изворима из Викидата.
Унутрашње
tokenizeName(fullName)
Претвара пуно име у пар {презимена одвојена размацима, имена одвојена размацима} . Реализовано у облицима који се могу пронаћи на Википодацима:
- Презиме, Име
- Презиме, Име Име
- Презиме Презиме, Име
- Име Име огли Презиме
- Име Име де Презиме
- Име … Име Презиме (најмање једно и не више од четири појединачна имена)
Овде име, за разлику од презимена, може бити почетно. Ако није испуњен ниједан од горњих формата, враћа се пуно име непромењено.
personNameToAuthorName(fullName)
Претвара пуно име у облик Презиме И. СИ. користећи tokenizeName.
personNameToResponsibleName(fullName)
Претвара пуно име у облик И. СИ. Презиме користећи tokenizeName.
getPeopleAsWikitext(context, value, options)
Претвара списак имена value у викитекст према списку опција options. Опције морају садржати следећа поља:
- separator — разделитељ на списку;
- conjunction — разделитељ пре последњег елемента списка;
- format — функција која трансформише имена у неком нормализованом облику (на пример, personNameToAuthorName);
- nolinks — логичка вредност, мора бити тачно ако је повезивање непожељно;
- preferids — логичка вредност, мора да буде тачно ако желите да вратите ид са Википодатака, а не имена.
Ако на спису има више аутора од броја maxAuthors (тренутно 10), остали се замењују са и др. или његових аналога (ако је језик одређен у контексту, тада i18nEtAl[context.lang], иначе се користи i18nEtAlDefault).
appendProperty(result, context, src, conjunctor, property, url)
Надодаје src[property] на result, раздвајајући их линијом уписаном conjunctor. Ако је могуће, формира везу до src[url].
generateAuthorLinks(context, src)
Враћа списак аутора src.author, оформљен путем getPeopleAsWikitext и уоквирен у <i class="wef_low_priority_links"></i>.
appendTitle(result, context, src)
Надодаје на result текстуални низ src.part // src.title или само src.title ако src.part није прецизирано. Ако је могуће уоквиривање src.part (или src.title ако src.part није прецизирано) у src.url.
appendLanguage(result, context, src)
Ако се context.lang разликује од i18nDefaultLanguage (српски у нашем случају), тада се назнака тога приписује result кроз Модул:Languages у формату {{ref-lang}}.
appendSubtitle(result, context, src)
Надодаје на result текстуални низ : src.subtitle ако је src.subtitle дефинисано.
appendOriginalTitle(result, context, src)
Надодаје на result текстуални низ = src.originaltitle ако је src.originaltitle дефинисано.
appendPublication(result, context, src)
Надодаје на result текстуални низ // src.publication: src.publication.subtitle ако је дефинисано src.publication.subtitle, или // src.publication ако је дефинисано src.publication.
appendEditor(result, context, src)
Надодаје на result текстуални низ / prefix src.editor ако је дефинисано src.editor, где је prefix дефинисано према context.lang (уобичајено, под ред.).
appendEdition(result, context, src)
Надодаје на result текстуални низ — src.edition ако је src.edition дефинисано.
appendPublicationData(result, context, src)
Надодаје на result текстуални низ у облику — src.place: src.publisher, src.year. ако је дефинисан бар један од наведених параметара. Неодређени део је изостављен, заједно са одговарајућом интерпункцијом. Дебело црево се користи само ако је наведено src.place и бар неки од src.publisher и src.year, зарез се ставља само ако је наведен и src.publisher, и src.year. Цртица и тачка користе се ако је наведен барем један од параметара.
appendVolumeAndIssue(result, context, src)
Надодаје на result текстуални низ у облику — letter_vol src.volume, letter_iss src.issue. ако је дефинисан бар један од наведених параметара. Зарез се користи ако су наведена оба параметра. letter_vol и letter_iss одређени на основу context.lang (на пример, Т. и вып. за руски текст, Vol. и Iss. за енглески).
appendPages(result, context, src)
Надодаје на result текстуални низ у облику — letter src.pages. ако је src.pages дефинисано, док је као сепаратор у src.pages, ако је распон страница, користи се симбол «—», а letter одређена на основу context.lang (на пример, P. за енглески и С. за руски).
appendNumberOfPages(result, context, src)
Надодаје на result текстуални низ у облику — src.numberOfPages letter ако је src.numberOfPages дефинисано. При чему је letter утврђено из context.lang (p. за енглески и с. за руски).
appendBookSeries(result, context, src)
Надодаје на result текстуални низ у облику — (src.bookSeries; letter_vol src.bookSeriesVolume, letter_iss src.bookSeriesIssue) ако је src.bookSeries дефинисано. Тачка са зарезом само ако је дефинисано src.bookSeriesVolume или src.bookSeriesIssue, зарез се користи ако су наведена оба параметра. letter_vol и letter_iss утврђено из context.lang, слично ономе како ради appendVolumeAndIssue.
appendBookSeries(result, context, src)
Надодаје на result информацију из src.tirage ако је дефинисано. Формат се одређује из context.lang, за енглески језик је то — ed. size: src.tirage, а за руски — src.tirage экз..
appendIdentifiers(result, context, src)
Надодаје на result идентификаторе ISBN, ISSN, DOI, PMID и arXiv ако су наведени. Идентификаторима се додељује цртица, тачнији формат је дефинисан у табелама options_commas, options_issn, options_doi, options_pmid и options_arxiv.
appendSourceId(result, context, src)
Надодаје на result у <span class="wikidata_cite citetype" data-entity-id="src.sourceId"></span>, где citetyle је src.type ако је ово поље дефинисано и citetype_unknown у супоротном случају.
appendAccessDate(result, context, src)
Надодаје на result текстуални низ у виду <small>Проверено dd month yyyy.</small>, где dd, month и yyyy потичу од src.accessdate ако је ово поље дефинисано.
populateUrl(context, src)
Ако је src.url недефинисан, али је src.sourceId познат, покушава доделити src.url везу.
populateYear(src)
Ако је src.year недефинисан, покушава да испуни са src.dateOfPublication и src.dateOfCreation.
populateTitle(src)
Ако је src.title недефинисан, покушава да придружи src.url, ако и ово није могуће, додељује ''(недефинисан наслов)''.
renderSource(context, src)
Унутрашња функција која генерише текст који ће се приказати у референци. Понаша се на следећи начин:
- Записује src.lang у context.lang (или i18nDefaultLanguage ако src.lang није записан).
- Позива populateUrl, populateTitle и populateYear.
- Формира променљиву result, с почетка дефинисану са generateAuthorLinks(context, src).
- Доследно примењује на result функцију appendTitle—appendAccessDate, док је блок appendEditor—appendAccessDate додатно уоквирен са
<span class="wef_low_priority_links"></span>
artificialSnaks(args)
Прави вештачки снек, која повезује извор са идентификатором frame.args[1] путем својства Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). и Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value)., а такође прослеђује и аргументе (том, издање итд.).
Услужни подмодули
- Модул:Sources/utils
- Модул:Sources-authors (не користи се)
- Модул:Sources-title (не користи се)
- Модул:Sources-year (не користи се)
Коришћена својства Википодатака
| Својство | Напомене |
|---|---|
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | користи се за означавање наслова чланка у енциклопедији |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | ако је потребно преправити назив ознаке ставке |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). | |
| Lua грешка in Модул:WD at line 450: attempt to index field 'wikibase' (a nil value). |
Тестови [ уређивање ]
Неуспелих тестова: 6
test_Sources:
| Текст | Очекивано | Стварно | |
|---|---|---|---|
| {{#invoke:Sources | renderSource | Q20750516}} | Президент Российской Федерации Указ Президента Российской Федерации от 15 јануара 1992 г. № 23 «О Генеральном директоре Агентства федеральной безопасности Российской Федерации и Министре внутренних дел Российской Федерации» (рус.) // Собрание законодательства Российской Федерации — 1992. | Lua грешка на линији 1113: attempt to index field 'wikibase' (a nil value). | |
| {{#invoke:Sources | renderSource | Q21683979}} | Advances in Cryptology — EUROCRYPT 2004 (енг.): International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004. Proceedings / ed.C. Cachin, J. L. Camenisch — Springer, Berlin, Heidelberg, 2004. — 630 p. — ISBN 978-3-540-21935-4 — doi:10.1007/B97182 | Lua грешка на линији 1113: attempt to index field 'wikibase' (a nil value). | |
| {{#invoke:Sources | renderSource | Q21683981}} | Nguyen P. Q. Can We Trust Cryptographic Software? Cryptographic Flaws in GNU Privacy Guard v1.2.3 (енг.) // Advances in Cryptology — EUROCRYPT 2004: International Conference on the Theory and Applications of Cryptographic Techniques, Interlaken, Switzerland, May 2-6, 2004. Proceedings / ed.C. Cachin, J. L. Camenisch — Springer, Berlin, Heidelberg, 2004. — P. 555—570. — 630 p. — ISBN 978-3-540-21935-4 — doi:10.1007/978-3-540-24676-3_33 | Lua грешка на линији 1113: attempt to index field 'wikibase' (a nil value). | |
| {{#invoke:Sources | renderSource | Q21725400}} | Eichenauer J., Lehn J. A non-linear congruential pseudo random number generator (енг.) // Statistische Hefte — Springer Berlin Heidelberg, 1986. — vol. 27, Iss. 1. — P. 315—326. — ISSN 0932-5026 — doi:10.1007/BF02932576 | Lua грешка на линији 1113: attempt to index field 'wikibase' (a nil value). | |
| {{#invoke:Sources | renderSource | Q21725116}} | Menezes A. J., Oorschot P. v., Vanstone S. A. Handbook of Applied Cryptography (енг.) — CRC Press, 1996. — 816 p. — (Discrete Mathematics and Its Applications) — ISBN 978-0-8493-8523-0 | Lua грешка на линији 1113: attempt to index field 'wikibase' (a nil value). | |
| {{#invoke:Sources | renderSource | Q27450585}} | Введение в криптографию (рус.) / под ред. В. В. Ященко — М.: МЦНМО, 2000. — 271 с. — ISBN 978-5-900916-26-2 | Lua грешка на линији 1113: attempt to index field 'wikibase' (a nil value). |
local p = {};
local i18nDefaultLanguage = 'ru';
local i18nEditors = {
fr = '',
de = 'Hrsg.: ',
es = '',
en = '',
it = '',
ru = 'под ред. ',
}
local i18nEtAlDefault = ' et al.';
local i18nEtAl = {
ru = ' и др.',
}
local i18nVolume = {
fr = 'Vol.',
es = 'Vol.',
en = 'Vol.',
it = 'Vol.',
ru = 'Т.',
}
local i18nIssue = {
en = 'Iss.',
ru = 'вып.',
}
local i18nPages = {
fr = 'P.',
de = 'S.',
es = 'P.',
en = 'P.',
it = 'P.',
ru = 'С.',
}
local i18nNumberOfPages = {
en = 'p.',
ru = 'с.',
}
local NORMATIVE_DOCUMENTS = {
Q20754888 = 'Закон Российской Федерации',
Q20754884 = 'Закон РСФСР',
Q20873831 = 'Распоряжение Президента Российской Федерации',
Q20873834 = 'Указ исполняющего обязанности Президента Российской Федерации',
Q2061228 = 'Указ Президента Российской Федерации',
}
local monthg = {'января', 'февраля', 'марта', 'апреля', 'мая', 'июня', 'июля', 'августа', "сентября", "октября", "ноября", "декабря"};
local PREFIX_CITEREF = "CITEREF_";
local options_arxiv = { separator = '; ', conjunction = '; ', format = function( id ) return '[http://arxiv.org/abs/' .. id .. ' arXiv:' .. id .. ']' end, nolinks = true, preferids = false };
local options_doi = { separator = '; ', conjunction = '; ', format = function( doi ) return '[http://dx.doi.org/' .. doi .. ' doi:' .. doi .. ']' end, nolinks = true, preferids = false };
local options_commas = { separator = ', ', conjunction = ', ', format = function( src ) return src end, nolinks = false, preferids = false };
local options_commas_short = { separator = ', ', conjunction = ', ', format = function( src ) return src end, nolinks = false, preferids = false, short = true };
local options_commas_nolinks = { separator = ', ', conjunction = ', ', format = function( src ) return src end, nolinks = true, preferids = false };
local options_commas_it = { separator = ', ', conjunction = ', ', format = function( src ) return "''" .. src .. "''" end, nolinks = false, preferids = false };
local options_commas_it_short = { separator = ', ', conjunction = ', ', format = function( src ) return "''" .. src .. "''" end, nolinks = false, preferids = false, short = true };
local options_commas_it_nolinks = { separator = ', ', conjunction = ', ', format = function( src ) return "''" .. src .. "''" end, nolinks = true , preferids = false };
local options_citetypes = { separator = ' ', conjunction = ' ', format = function( src ) return 'citetype_' .. src end, nolinks = true , preferids = true };
function assertNotNull( argName, arg )
if ( (not arg) or (arg == nil) ) then
error( argName .. ' is not specified' )
end
end
function coalesce( arg1, arg2, arg3, arg4 )
if ( not isEmpty( arg1 ) ) then return arg1 end
if ( not isEmpty( arg2 ) ) then return arg2 end
if ( not isEmpty( arg3 ) ) then return arg3 end
if ( not isEmpty( arg4 ) ) then return arg4 end
return nil;
end
function isEmpty( str )
return ( not str ) or ( str == nil ) or ( #str == 0 );
end
function isInstanceOf( entity, typeEntityId )
if ( not entity or not entity.claims or not entity.claims.P31 ) then
return false;
end
for _, claim in pairs( entity.claims.P31 ) do
if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value["numeric-id"] ) then
local actualTypeId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
if ( actualTypeId == typeEntityId ) then
return true;
end
end
end
return false;
end
function getEntity( context, entityId )
assertNotNull( 'context', context );
assertNotNull( 'entityId', entityId );
local cached = context.cache[ entityId ];
if ( cached ) then return cached; end;
local result = mw.wikibase.getEntity( entityId );
if ( result ) then
context.cache[ entityId ] = result;
end
return result;
end
function toStringSnak( propertyId, strValue )
assertNotNull('propertyId', strValue)
assertNotNull('strValue', strValue)
local snak = { snaktype = "value", property = propertyId, datatype = 'string'};
snak["datavalue"] = { value = strValue, type = 'string' };
return snak;
end
function toUrlSnak( propertyId, strValue )
assertNotNull('propertyId', strValue)
assertNotNull('strValue', strValue)
local snak = { snaktype = "value", property = propertyId, datatype = 'string'};
snak["datavalue"] = { value = strValue, type = 'url' };
return snak;
end
function toWikibaseEntityIdSnak( propertyId, entityId )
assertNotNull('propertyId', entityId)
assertNotNull('entityId', entityId)
if ( mw.ustring.sub( entityId, 1, 1 ) ~= 'Q' ) then error( 'Incorrect entity ID: «' .. entityId .. '»' ); end;
local value = {};
value["entity-type"] = 'item';
value["numeric-id"] = mw.ustring.sub( entityId , 2);
local snak = { snaktype = "value", property = propertyId, datatype = 'wikibase-item'};
snak["datavalue"] = { value = value, type = 'wikibase-entityid' };
return snak;
end
function renderSource( context, src )
mw.logObject( src );
context.lang = getLangCode( getSingle( src.lang ) ) or i18nDefaultLanguage;
preprocessPlaces( src, context.lang );
src.title = src.title or getSingle( src.url ) or '\'\'(unspecified title)\'\''
if ( src.entityId and not src.url ) then
local entity = getEntity( context, src.entityId );
if ( entity.sitelinks and entity.sitelinks[ context.lang .. 'wikisource'] ) then
src.url = ':' .. context.lang .. ':s:' .. entity.sitelinks[ context.lang .. 'wikisource' ].title;
end
end
if ( not src.year and src.dateOfPublication ) then
local date = getSingle( src.dateOfPublication );
src.year = mw.ustring.sub( date, 2, 5 );
end
if ( not src.year and src.dateOfCreation ) then
local date = getSingle( src.dateOfCreation );
src.year = mw.ustring.sub( date, 2, 5 );
end
local result;
if ( src.author ) then
result = getPeopleAsAuthorWikitext( context, src.author, options_commas );
end
if ( not isEmpty( result )) then
result = '\'\'' .. result .. '\'\' ';
else
result = '';
end
if ( src.part ) then
if ( src.url ) then
result = result .. wrapInUrl( src.url, toString( context, src.part, options_commas_nolinks ) );
else
result = result .. toString( context, src.part, options_commas );
end
result = result .. ' // ' .. toString( context, src.title, options_commas );
else
-- title only
if ( src.url ) then
result = result .. wrapInUrl( src.url, toString( context, src.title, options_commas_nolinks ) );
else
result = result .. toString( context, src.title, options_commas );
end
end
if ( src.subtitle ) then
result = result .. ": " .. toString( context, src.subtitle, options_commas );
end
if ( src.originaltitle ) then
result = result .. ' = ' .. toString( context, src.originaltitle, options_commas );
end
if ( src.publication ) then
if ( type( src.publication.title or '') ~= 'string' ) then error('type of src.publication.title is not string but ' .. type( src.publication.title ) ) end;
result = result .. ' // ' .. toString( context, src.publication, options_commas_it_short );
if ( src.publication.subtitle ) then
result = result .. ': ' .. toString( context, src.publication.subtitle, options_commas_it_short );
end
end
if ( src.editor ) then
local prefix = i18nEditors[ context.lang ] or i18nEditors[ i18nDefaultLanguage ];
result = result .. ' / ' .. prefix .. toString( context, src.editor, options_commas );
end
if ( src.place or src.publisher or src.year ) then
result = result .. ' — ';
if ( src.place ) then
result = result .. toString( context, src.place, options_commas_short );
if ( src.publisher or src.year ) then
result = result .. ': ';
end
end
if ( src.publisher ) then
result = result .. toString( context, src.publisher, options_commas_short );
if ( src.year ) then
result = result .. ', ';
end
end
if ( src.year ) then
result = result .. toString( context, src.year, options_commas );
end
result = result .. '.';
end
if ( src.volume or src.issue ) then
result = result .. ' — ';
if ( src.volume ) then
local letter = i18nVolume[ context.lang ] or i18nVolume[ i18nDefaultLanguage ];
result = result .. letter .. ' ' .. toString( context, src.volume, options_commas );
if ( src.issue ) then
local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
result = result .. ', ' .. letter .. ' ' .. toString( context, src.issue, options_commas ) .. '.';
else
result = result .. '.';
end
else
local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
result = result .. letter .. ' ' .. toString( context, src.issue, options_commas ) .. '.';
end
end
if ( src.pages ) then
local letter = i18nPages[ context.lang ] or i18nPages[ i18nDefaultLanguage ];
result = result .. ' — ' .. letter .. ' ' .. toString( context, src.pages, options_commas ) .. '.';
end
if ( src.numberOfPages ) then
local letter = i18nNumberOfPages[ context.lang ] or i18nNumberOfPages[ i18nDefaultLanguage ];
result = result .. ' — ' .. toString( context, src.numberOfPages, options_commas ) .. ' ' .. letter;
end
if ( src.bookSeries ) then
result = result .. ' — (' .. toString( context, src.bookSeries, options_commas )
if ( src.bookSeriesVolume or src.bookSeriesIssue ) then
result = result .. '; ';
if ( src.bookSeriesVolume ) then
local letter = i18nVolume[ context.lang ] or i18nVolume[ i18nDefaultLanguage ];
result = result .. letter .. ' ' .. toString( context, src.bookSeriesVolume, options_commas );
if ( src.bookSeriesIssue ) then
local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
result = result .. ', ' .. letter .. ' ' .. toString( context, src.bookSeriesIssue, options_commas );
else
result = result;
end
else
local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
result = result .. letter .. ' ' .. toString( context, src.bookSeriesIssue, options_commas );
end
end
result = result .. ')';
end
if ( src.isbn ) then
result = result .. ' — ISBN ' .. toString( context, src.isbn, options_commas );
end
if ( src.issn ) then
result = result .. ' — ISSN ' .. toString( context, src.issn, options_commas );
end
if ( src.doi ) then
result = result .. ' — ' .. toString( context, src.doi, options_doi );
end
if ( src.arxiv ) then
result = result .. ' — ' .. toString( context, src.arxiv, options_arxiv );
end
if ( src.entityId ) then
if ( src.type and src.entityId ) then
-- wrap into span to target from JS
result = '<span class="wikidata_cite ' .. toString( context, src.type, options_citetypes ) .. '" data-entity-id="' .. getSingle( src.entityId ) .. '">' .. result .. '</span>'
else
result = '<span class="wikidata_cite citetype_unknown" data-entity-id="' .. getSingle( src.entityId ) .. '">' .. result .. '</span>'
end
end
if ( src.accessdate ) then
local date = getSingle( src.accessdate );
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T";
local y, m, d = mw.ustring.match( date , pattern );
y,m,d = tonumber(y),tonumber(m),tonumber(d);
result = result .. " <small>Проверено " .. tostring(d) .. " " .. monthg[m] .. " " .. tostring(y) .. ".</small>";
end
-- append invisible links to all elements used by source for tracking purposes
local result = result .. '<div style="display:none">';
for key, entity in pairs( context.cache ) do
result = result .. '[[d:Track:' .. key .. ']]';
end
result = result ..'</div>'
return {text = result, code = src.code};
end
function wrapInUrl( urls, text )
local url = getSingle( urls );
if ( string.sub( url, 1, 1 ) == ':' ) then
return '[[' .. url .. '|' .. text .. ']]';
else
return '[' .. url .. ' ' .. text .. ']';
end
end
function renderShortReference( src )
context = {
cache = {},
lang = getSingle( src.lang ) or i18nDefaultLanguage;
};
src.title = src.title or '\'\'(unspecified title)\'\''
local result = '[[#' .. PREFIX_CITEREF .. src.code .. '|';
if ( src.author ) then
result = result .. toString( context, src.author, options_authors_nolinks );
else
result = result .. toString( context, src.title, options_commas_it_nolinks );
end
result = result .. ']]'
if ( src.year ) then
result = result .. ', ' .. toString( context, src.year, options_commas );
end
if ( src.volume ) then
local letter = i18nVolume[ context.lang ] or i18nVolume[ i18nDefaultLanguage ];
result = result .. ' — ' .. letter .. ' ' .. toString( context, src.volume, options_commas ) .. '.';
end
if ( src.issue ) then
local letter = i18nIssue[ context.lang ] or i18nIssue[ i18nDefaultLanguage ];
result = result .. ' — ' .. letter .. ' ' .. toString( context, src.issue, options_commas ) .. '.';
end
if ( src.pages ) then
local letter = i18nPages[ context.lang ] or i18nPages[ i18nDefaultLanguage ];
result = result .. ' — ' .. letter .. ' ' .. toString( context, src.pages, options_commas ) .. '.';
end
end
function getSingle( value )
if ( not value ) then
return;
end
if ( type( value ) == 'string' ) then
return value;
elseif ( type( value ) == 'table' ) then
if ( value.id ) then
return value.id;
end
for i, tableValue in pairs( value ) do
return getSingle( tableValue );
end
end
return '(unknown)';
end
function toString( context, value, options )
if ( type( value ) == 'string' ) then
return options.format( value );
elseif ( type( value ) == 'table' ) then
if ( value.id ) then
-- this is link
if ( type( value.label or '' ) ~= 'string' ) then mw.logObject( value ); error('label of table value is not string but ' .. type( value.label ) ) end
if ( options.preferids ) then
return options.format( value.id );
else
if ( options.nolinks ) then
return options.format( value.label or mw.wikibase.label( value.id ) or '\'\'(untranslated title)\'\'' );
else
return options.format( renderLink( context, value.id, value.label, options ) );
end
end
end
local resultList = {};
for i, tableValue in pairs( value ) do
table.insert( resultList, toString( context, tableValue, options ) );
end
return mw.text.listToText( resultList, options.separator, options.conjunction);
else
return options.format( '(unknown type)' );
end
return '';
end
function renderLink( context, entityId, customTitle, options )
if ( not entityId ) then error("entityId is not specified") end
if ( type( entityId ) ~= 'string' ) then error('entityId is not string, but ' .. type( entityId ) ) end
if ( type( customTitle or '' ) ~= 'string' ) then error('customTitle is not string, but ' .. type( customTitle ) ) end
local title = customTitle;
if ( isEmpty( title ) ) then
local entity = getEntity( context, entityId );
-- ISO 4
if ( isEmpty( title ) ) then
if ( entity.claims and entity.claims.P1160 ) then
for _, claim in pairs( entity.claims.P1160 ) do
if ( claim
and claim.mainsnak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.value
and claim.mainsnak.datavalue.value.language == context.lang ) then
title = claim.mainsnak.datavalue.value.text;
mw.log('Got title of ' .. entityId .. ' from ISO 4 claim: «' .. title .. '»' )
break;
end
end
end
end
-- official name P1448
-- short name P1813
if ( isEmpty( title ) and options.short ) then
if ( entity.claims and entity.claims.P1813 ) then
for _, claim in pairs( entity.claims.P1813 ) do
if ( claim
and claim.mainsnak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.value
and claim.mainsnak.datavalue.value.language == context.lang ) then
title = claim.mainsnak.datavalue.value.text;
mw.log('Got title of ' .. entityId .. ' from short name claim: «' .. title .. '»' )
break;
end
end
end
end
-- person name P1559
-- labels
if ( isEmpty( title ) and entity.labels[ context.lang ] ) then
title = entity.labels[ context.lang ].value;
mw.log('Got title of ' .. entityId .. ' from label: «' .. title .. '»' )
end
end
local actualText = title or '\'\'(untranslated)\'\'';
local link = getElementLink( context, entityId, entity);
return wrapInUrl( link, actualText );
end
function getElementLink( context, entityId, entity )
-- fast sitelink lookup, not an expensive operation
local link = mw.wikibase.sitelink( entityId )
if ( link ) then return ':' .. link end
if ( not entity and entityId ) then
entity = getEntity( context, entityId )
end
if ( entity ) then
-- link to entity in source context language
local projectToCheck = context.lang .. 'wiki';
if ( entity.sitelinks and entity.sitelinks[ projectToCheck ] ) then
return ':' .. context.lang .. ':' .. entity.sitelinks[ projectToCheck ].title;
end
end
if ( entityId ) then return ':d:' .. entityId end;
-- if ( entityId ) then return 'https://tools.wmflabs.org/reasonator/?q=' .. entityId .. '&lang=ru' end;
return nil;
end
function getPeopleAsAuthorWikitext( context, value, options )
if ( type( value ) == 'string' ) then
return personNameToAuthorName( value );
elseif ( type( value ) == 'table' ) then
if ( value.id ) then
-- this is link
if ( options.preferids ) then
return value.id;
else
if ( options.nolinks ) then
return getPersonNameAsAuthorLabel( context, value.id, value.label, options );
else
return getPersonNameAsAuthorWikitext( context, value.id, value.label, options );
end
end
end
local resultList = {};
for i, tableValue in pairs( value ) do
local nextWikitext = getPeopleAsAuthorWikitext( context, tableValue, options );
if ( not isEmpty( nextWikitext ) ) then
table.insert( resultList, nextWikitext );
if ( #resultList == 4 ) then
-- even 4 is too much, but we preserve 4th to mark that "it's more than 3"
break;
end
end
end
local resultWikitext = '';
for i, wikitext in pairs( resultList ) do
if ( i == 4 ) then
resultWikitext = resultWikitext .. ( i18nEtAl[ context.lang ] or i18nEtAlDefault );
break;
end
if ( i ~= 1 ) then
resultWikitext = resultWikitext .. ', ';
end
resultWikitext = resultWikitext .. wikitext;
end
return resultWikitext;
end
return options.format( '(unknown type)' );
end
function getPersonNameAsAuthorWikitext( context, entityId, customLabel, options )
local personNameAsAuthor = getPersonNameAsAuthorLabel( context, entityId, customLabel, options);
if ( personNameAsAuthor == nil ) then
return nil;
end
local link = getElementLink( context, entityId, nil );
return wrapInUrl( link, personNameAsAuthor );
end
function getPersonNameAsAuthorLabel( context, entityId, providedLabel, options )
-- would custom label provided we don't need to check entity at all
if ( not isEmpty( providedLabel ) ) then
mw.log( 'Custom label provided for ' .. entityId );
return personNameToAuthorName( providedLabel );
end
local entity = getEntity( context, entityId );
if ( not entity ) then return '\'\'(entity ' .. entityId .. ' is missing)\'\'' end;
if ( not isInstanceOf( entity, 'Q5' ) ) then
mw.log( 'Entity ' .. entityId .. ' is not a person' );
return nil;
end
local personName = nil;
-- support only labels so far
if ( entity.labels[ context.lang ] ) then
personName = entity.labels[ context.lang ].value;
mw.log('Got person name of ' .. entityId .. ' from label: «' .. personName .. '»' )
end
if ( isEmpty( personName ) ) then
return '\'\'(not translated to ' .. context.lang .. ')\'\'';
else
return personNameToAuthorName( personName );
end
end
function personNameToAuthorName( fullName )
if ( not fullName ) then return fullName; end
local f, i, o = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)\,%s(%a[%a\-]*)%s(%a[%a\-]*)%s*$' );
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Fa, I. O.» match' );
return f .. ' '
.. mw.ustring.sub( i, 1, 1 ) .. '. '
.. mw.ustring.sub( o, 1, 1 ) .. '.';
end
local f1, f2, i = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a[%a\-]*)\,%s(%a[%a\-]*)%s*$' );
if ( f1 ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Fa Fa, I» match' );
return f1 .. ' ' .. f2 .. ' '
.. mw.ustring.sub( i, 1, 1 ) .. '.';
end
local i, o, f = mw.ustring.match( fullName, '^%s*(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I. O. Fa» match' );
return f .. ' ' .. i .. '. ' .. o .. '.';
end
local i1, i2, i3, f = mw.ustring.match( fullName, '^%s*(%a)\.%s(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I. O. ?. Fa» match' );
return f .. ' ' .. i1 .. '. ' .. i2 .. '. ' .. i3 .. '.';
end
-- Joel J. P. C. Rodrigues
local i1, i2, i3, i4, f = mw.ustring.match( fullName, '^%s*(%a)[%a\-]+%s(%a)\.%s(%a)\.%s(%a)\.%s(%a[%a\-]+)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «I. O. ?. Fa» match' );
return f .. ' ' .. i1 .. '. ' .. i2 .. '. ' .. i3 .. '. ' .. i4 .. '.';
end
local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a)\.%s(%a[%a\-]*)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im O. Fa» match' );
return f .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. o .. '.';
end
local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]*)%s(%a[%a\-]*)%s(%a[%a\-]*)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im Ot Fa» match' );
return f .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. mw.ustring.sub( o, 1, 1 ) .. '.';
end
local i, o, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]+)%s(%a[%a\-]+)%s+оглы%s+(%a[%a\-]+)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im Ot оглы Fa» match' );
return f .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '. ' .. mw.ustring.sub( o, 1, 1 ) .. '.';
end
local i, f = mw.ustring.match( fullName, '^%s*(%a[%a\-]+)%s(%a[%a\-]+)%s*$');
if ( f ) then
mw.log( 'personNameToAuthorName: «' .. fullName .. '»: have «Im Fa» match' );
return f .. ' ' .. mw.ustring.sub( i, 1, 1 ) .. '.';
end
mw.log( 'Unmatched any pattern: «' .. fullName .. '»' );
return fullName;
end
-- Expand special types of references when additional data could be found in OTHER entity properties
function expandSpecials( currentEntity, reference, data )
if ( reference.snaks.P248
and reference.snaks.P248[1]
and reference.snaks.P248[1].datavalue
and reference.snaks.P248[1].datavalue.value["numeric-id"]) then
local sourceId = "Q" .. reference.snaks.P248[1].datavalue.value["numeric-id"];
-- Gemeinsame Normdatei -- specified by P227
if ( sourceId == 'Q36578' ) then
appendSnaks( currentEntity.claims, 'P227', data, 'title', { format = function( gnd ) return 'Record #' .. gnd; end } );
appendSnaks( currentEntity.claims, 'P227', data, 'url', { format = function( gnd ) return 'http://d-nb.info/gnd/' .. gnd .. '/'; end } );
data.publication = { id = 'Q36578', label = 'Gemeinsame Normdatei' }
data.year = '2012—2015'
end
-- BNF -- specified by P268
if ( sourceId == 'Q15222191' ) then
appendSnaks( currentEntity.claims, 'P268', data, 'title', { format = function( id ) return 'Record #' .. id; end } );
appendSnaks( currentEntity.claims, 'P268', data, 'url', { format = function( id ) return 'http://catalogue.bnf.fr/ark:/12148/cb' .. id; end } );
expandSpecialsQualifiers( currentEntity, 'P268', data );
end
-- Find a Grave -- specified by P535
if ( sourceId == 'Q63056' ) then
appendSnaks( currentEntity.claims, 'P535', data, 'url', { format = function( id ) return 'http://www.findagrave.com/cgi-bin/fg.cgi?page=gr&GRid=' .. id; end } );
expandSpecialsQualifiers( currentEntity, 'P535', data );
end
-- Dizionario Biografico degli Italiani -- specified by P1986
if ( sourceId == 'Q1128537' ) then
if ( not data.lang ) then data.lang = { id = 'Q652' } end;
appendSnaks( currentEntity.claims, 'P1986', data, 'url', { format = function( id ) return 'http://www.treccani.it/enciclopedia/' .. id .. '_%28Dizionario_Biografico%29/' end } );
expandSpecialsQualifiers( currentEntity, 'P1986', data );
end
-- Union List of Artist Names -- specified by P245
if ( sourceId == 'Q2494649' ) then
appendSnaks( currentEntity.claims, 'P245', data, 'url', { format = function( id ) return 'http://www.getty.edu/vow/ULANFullDisplay?find=&role=&nation=&subjectid=' .. id end } );
expandSpecialsQualifiers( currentEntity, 'P245', data );
end
-- Gran Enciclopèdia Catalana -- specified by P1296
if ( sourceId == 'Q2664168' ) then
appendSnaks( currentEntity.claims, 'P1296', data, 'url', { format = function( id ) return 'http://www.enciclopedia.cat/enciclop%C3%A8dies/gran-enciclop%C3%A8dia-catalana/EC-GEC-' .. id .. '.xml'; end } );
expandSpecialsQualifiers( currentEntity, 'P1296', data );
end
-- Encyclopædia Britannica online -- specified by P1417
if ( sourceId == 'Q5375741' ) then
appendSnaks( currentEntity.claims, 'P1417', data, 'url', { format = function( id ) return 'http://global.britannica.com/' .. id; end } );
expandSpecialsQualifiers( currentEntity, 'P1417', data );
end
-- Electronic Jewish Encyclopedia (Elektronnaja Evrejskaja Entsiklopedia) -- specified by P1438
if ( sourceId == 'Q1967250' ) then
appendSnaks( currentEntity.claims, 'P1438', data, 'url', { format = function( id ) return 'http://www.eleven.co.il/article/' .. id; end } );
expandSpecialsQualifiers( currentEntity, 'P1438', data );
end
-- sports-reference.com -- specified by P1447
if ( sourceId == 'Q18002875' ) then
appendSnaks( currentEntity.claims, 'P1447', data, 'url', { format = function( id ) return 'http://www.sports-reference.com/olympics/athletes/' .. id .. '.html'; end } );
expandSpecialsQualifiers( currentEntity, 'P1447', data );
end
end
end
function expandSpecialsQualifiers( entity, propertyId, result )
if ( entity.claims ~= nil and entity.claims[propertyId] ~= nil ) then
local claims = entity.claims[propertyId];
appendQualifiers( claims, 'P958', result, 'part', {} );
appendQualifiers( claims, 'P953', result, 'url', {} );
appendQualifiers( claims, 'P1065', result, 'url', {} );
appendQualifiers( claims, 'P854', result, 'url', {} );
appendQualifiers( claims, 'P357', result, 'title', {} ); -- obsolete
appendQualifiers( claims, 'P1476', result, 'title', {} );
appendQualifiers( claims, 'P478', result, 'volume', {} );
appendQualifiers( claims, 'P433', result, 'issue', {} );
end
end
function findClaimsByValue( entity, propertyId, value )
local result = {};
if ( entity and entity.claims and entity.claims[propertyId] ) then
for i, claim in pairs( entity.claims[propertyId] ) do
if ( claim.mainsnak and claim.mainsnak.datavalue ) then
local datavalue = claim.mainsnak.datavalue;
if ( datavalue.type == "string" and datavalue.value == value
or datavalue.type == "wikibase-entityid" and datavalue.value["entity-type"] == "item" and tostring( datavalue.value["numeric-id"] ) == mw.ustring.sub( value, 2 ) ) then
table.insert( result, claim );
end
end
end
end
return result;
end
function appendSnaks( allSnaks, snakPropertyId, result, property, options )
-- do not populate twice
if ( result[property] ) then return result end;
if ( not allSnaks ) then return result; end;
local selectedSnakes = allSnaks[ snakPropertyId ];
if ( not selectedSnakes ) then return result; end;
local hasPreferred = false;
for k, snak in pairs( selectedSnakes ) do
if ( snak and snak.mainsnak and snak.mainsnak.datavalue and snak.rank == 'preferred' ) then
--it's a preferred claim
appendImpl( snak.mainsnak.datavalue, snak.qualifiers, result, property, options );
hasPreferred = true;
end
end
if ( hasPreferred ) then return result; end;
for k, snak in pairs( selectedSnakes ) do
if ( snak and snak.mainsnak and snak.mainsnak.datavalue and snak.rank ~= 'deprecated' ) then
--it's a claim
appendImpl( snak.mainsnak.datavalue, snak.qualifiers, result, property, options );
elseif ( snak and snak.datavalue ) then
-- it's a snak
appendImpl( snak.datavalue, nil, result, property, options );
end
end
end
function appendQualifiers( claims, qualifierPropertyId, result, resultProperty, options )
-- do not populate twice
if ( not claims ) then return result end;
if ( result[resultProperty] ) then return result end;
for i, claim in pairs( claims ) do
if ( claim.qualifiers and claim.qualifiers[ qualifierPropertyId ] ) then
for k, qualifier in pairs( claim.qualifiers[ qualifierPropertyId ] ) do
if ( qualifier and qualifier.datavalue ) then
appendImpl( qualifier.datavalue, nil, result, resultProperty, options );
end
end
end
end
end
function appendImpl( datavalue, qualifiers, result, property, options )
if ( datavalue.type == 'string' ) then
local value = datavalue.value;
if ( options.format ) then
value = options.format( value );
end
appendImpl_toTable( result, property );
table.insert( result[property], value);
elseif ( datavalue.type == 'monolingualtext' ) then
local value = datavalue.value.text;
if ( options.format ) then
value = options.format( value );
end
appendImpl_toTable( result, property );
table.insert( result[property], value);
elseif ( datavalue.type == 'quantity' ) then
local value = datavalue.value.amount;
if ( mw.ustring.sub( value , 1, 1 ) == '+' ) then
value = mw.ustring.sub( value , 2 );
end
if ( options.format ) then
value = options.format( value );
end
appendImpl_toTable( result, property );
table.insert( result[property], value);
elseif ( datavalue.type == 'wikibase-entityid' ) then
local value = datavalue.value;
appendImpl_toTable( result, property );
local toInsert = {
id = 'Q' .. value["numeric-id"],
label = getSingleStringQualifierValue(qualifiers, 'P1932') -- stated as
};
table.insert( result[property], toInsert );
elseif datavalue.type == 'time' then
local value = datavalue.value;
if ( options.format ) then
value = options.format( value );
end
appendImpl_toTable( result, property );
table.insert( result[property], tostring( value.time ));
end
end
function appendImpl_toTable(result, resultProperty)
if ( not result[resultProperty] ) then
result[resultProperty] = {};
elseif ( type( result[resultProperty] ) == 'string' or ( type( result[resultProperty] ) == 'table' and type( result[resultProperty].id ) == 'string' ) ) then
result[resultProperty] = { result[resultProperty] };
end
end
function getSingleStringQualifierValue( allQualifiers, qualifierPropertyId )
if ( not allQualifiers ) then return end
if ( not allQualifiers[qualifierPropertyId] ) then return end
for k, qualifier in pairs( allQualifiers[qualifierPropertyId] ) do
if ( qualifier and qualifier.datatype == 'string'
and qualifier.datavalue and qualifier.datavalue.type == 'string' and not isEmpty( qualifier.datavalue.value ) ) then
return qualifier.datavalue.value;
end
end
return;
end
function expandDescribed ( context, sourceEntity, data )
local described = data.described;
-- use only first one
if ( type( described ) == 'table' and described[1] and described[1].id ) then
data.described = described[1];
described = data.described;
end
data.publication = data.described;
if ( described and described.id ) then
if ( sourceEntity ) then
-- do we have appropriate record in P1433 ?
local claims = findClaimsByValue( sourceEntity, 'P1343', described.id );
if ( claims and #claims ~= 0 ) then
appendQualifiers( claims, 'P958', data, 'part', {} );
appendQualifiers( claims, 'P50', data, 'author', {} );
appendQualifiers( claims, 'P953', data, 'url', {} );
appendQualifiers( claims, 'P1065', data, 'url', {} );
appendQualifiers( claims, 'P854', data, 'url', {} );
appendQualifiers( claims, 'P357', data, 'title', {} ); -- obsolete
appendQualifiers( claims, 'P1476', data, 'title', {} );
appendQualifiers( claims, 'P478', data, 'volume', {} );
end
end
local titleWerePresent = not (not data.title);
local desEntity = getEntity( context, described.id );
if ( desEntity ) then
populateSourceDataImpl( desEntity, data );
if ( titleWerePresent and isEmpty( data.publication.label ) ) then
appendSnaks( desEntity.claims, 'P1160', data, 'publication-title', {} ); -- obsolete
data.publication.label = getSingle( data['publication-title'] );
end
if ( titleWerePresent and isEmpty( data.publication.label ) ) then
appendSnaks( desEntity.claims, 'P357', data, 'publication-title', {} ); -- obsolete
appendSnaks( desEntity.claims, 'P1476', data, 'publication-title', {} );
appendSnaks( desEntity.claims, 'P1680', data, 'publication-subtitle', {} );
data.publication.label = getSingle( data['publication-title'] );
data.publication.subtitle = getSingle( data['publication-subtitle'] );
end
end
end
end
function expandPublication( context, sourceEntity, data )
local publication = data.publication;
-- use only first one
if ( type( publication ) == 'table' and publication[1] and publication[1].id ) then
data.publication = publication[1];
publication = data.publication;
end
if ( not publication ) then return end;
if ( not publication.id ) then return end;
if ( sourceEntity ) then
-- do we have appropriate record in P1433 ?
local claims = findClaimsByValue( sourceEntity, 'P1433', publication.id );
if ( claims and #claims ~= 0 ) then
appendQualifiers( claims, 'P958', data, 'part', {} );
appendQualifiers( claims, 'P953', data, 'url', {} );
appendQualifiers( claims, 'P1065', data, 'url', {} );
appendQualifiers( claims, 'P854', data, 'url', {} );
appendQualifiers( claims, 'P856', data, 'url', {} );
appendQualifiers( claims, 'P123', data, 'publisher', {} );
appendQualifiers( claims, 'P291', data, 'place', {} );
appendQualifiers( claims, 'P304', data, 'pages', {} );
appendQualifiers( claims, 'P1104', data, 'numberOfPages', {} );
appendQualifiers( claims, 'P478', data, 'volume', {} );
appendQualifiers( claims, 'P433', data, 'issue', {} );
appendQualifiers( claims, 'P571', data, 'dateOfCreation', {} );
appendQualifiers( claims, 'P577', data, 'dateOfPublication', {} );
appendQualifiers( claims, 'P212', data, 'isbn', {} ); -- ISBN-13
appendQualifiers( claims, 'P957', data, 'isbn', {} ); -- ISBN-10
end
end
local titleWerePresent = not (not data.title);
local pubEntity = getEntity( context, publication.id );
populateSourceDataImpl( pubEntity, data );
if ( titleWerePresent and isEmpty( data.publication.label ) ) then
appendSnaks( pubEntity.claims, 'P1160', data, 'publication-title', {} ); -- obsolete
data.publication.label = getSingle( data['publication-title'] );
end
if ( titleWerePresent and isEmpty( data.publication.label ) ) then
appendSnaks( pubEntity.claims, 'P357', data, 'publication-title', {} ); -- obsolete
appendSnaks( pubEntity.claims, 'P1476', data, 'publication-title', {} );
appendSnaks( pubEntity.claims, 'P1680', data, 'publication-subtitle', {} );
data.publication.label = getSingle( data['publication-title'] );
data.publication.subtitle = getSingle( data['publication-subtitle'] );
end
if ( pubEntity.claims and pubEntity.claims.P361 ) then
for c, claim in pairs( pubEntity.claims.P361 ) do
if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value["numeric-id"] ) then
local possibleBookSeriesEntityId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
local possibleBookSeriesEntity = getEntity( context, possibleBookSeriesEntityId );
if ( isInstanceOf( possibleBookSeriesEntity, 'Q277759' ) ) then
appendImpl_toTable( data, 'bookSeries' );
table.insert( data.bookSeries, { id = possibleBookSeriesEntityId } );
appendQualifiers( { claim }, 'P478', data, 'bookSeriesVolume', {} );
appendQualifiers( { claim }, 'P433', data, 'bookSeriesIssue', {} );
end
end
end
end
expandBookSeries( context, data );
end
function expandBookSeries( context, data )
local bookSeries = data.bookSeries;
if ( not bookSeries ) then return end;
-- use only first one
if ( type( bookSeries ) == 'table' and bookSeries[1] and bookSeries[1].id ) then
data.bookSeries = bookSeries[1];
bookSeries = data.bookSeries;
end
if ( not bookSeries ) then return end;
if ( not bookSeries.id ) then return end;
local bookSeriesEntity = getEntity( context, bookSeries.id );
appendSnaks( bookSeriesEntity.claims, 'P123', data, 'publisher', {} );
appendSnaks( bookSeriesEntity.claims, 'P291', data, 'place', {} );
appendSnaks( bookSeriesEntity.claims, 'P236', data, 'issn', {} );
end
function populateSourceDataImpl( entity, plainData )
populateDataFromClaims( entity.id, entity.claims, plainData );
local normativeTitle = getNormativeTitle( entity )
if ( normativeTitle ) then
local y, m, d = mw.ustring.match( getSingle( plainData.dateOfCreation ) , "(%-?%d+)%-(%d+)%-(%d+)T" );
y,m,d = tonumber(y),tonumber(m),tonumber(d);
local title = toString( { lang='ru' }, plainData.title, options_commas_nolinks );
plainData.title = { normativeTitle .. " от " .. tostring(d) .. " " .. monthg[m] .. " " .. tostring(y) .. " г. № " .. getSingle( plainData.docNumber ) .. ' «' .. title.. '»' }
end
if ( not plainData.title ) then
if ( entity.labels and entity.labels.ru and entity.labels.ru.value ) then
plainData.title = { entity.labels.ru.value };
end
end
return plainData;
end
function populateDataFromClaims( entityId, claims, data )
appendSnaks( claims, 'P50', data, 'author', {} );
appendSnaks( claims, 'P407', data, 'lang', {} );
appendSnaks( claims, 'P364', data, 'lang', {} );
appendSnaks( claims, 'P958', data, 'part', {} );
if ( not data.title ) then
if ( not isEmpty( entityId ) ) then
local optionsAsLinks = { format = function( text ) return { id = entityId, label = text } end };
appendSnaks( claims, 'P357', data, 'title', optionsAsLinks ); -- obsolete
appendSnaks( claims, 'P1476', data, 'title', optionsAsLinks );
else
appendSnaks( claims, 'P357', data, 'title', {} ); -- obsolete
appendSnaks( claims, 'P1476', data, 'title', {} );
end
appendSnaks( claims, 'P1680', data, 'subtitle', {} );
end
appendSnaks( claims, 'P953', data, 'url', {} );
appendSnaks( claims, 'P1065', data, 'url', {} );
appendSnaks( claims, 'P854', data, 'url', {} );
appendSnaks( claims, 'P856', data, 'url', {} );
appendSnaks( claims, 'P1343', data, 'described', {} );
appendSnaks( claims, 'P1433', data, 'publication', {} );
appendSnaks( claims, 'P123', data, 'publisher', {} );
appendSnaks( claims, 'P291', data, 'place', {} );
appendSnaks( claims, 'P304', data, 'pages', {} );
appendSnaks( claims, 'P1104', data, 'numberOfPages', {} );
appendSnaks( claims, 'P478', data, 'volume', {} );
appendSnaks( claims, 'P433', data, 'issue', {} );
appendSnaks( claims, 'P571', data, 'dateOfCreation', {} );
appendSnaks( claims, 'P577', data, 'dateOfPublication', {} );
appendSnaks( claims, 'P212', data, 'isbn', {} ); -- ISBN-13
appendSnaks( claims, 'P957', data, 'isbn', {} ); -- ISBN-10
appendSnaks( claims, 'P236', data, 'issn', {} );
-- web
-- appendSnaks( claims, 'P813', data, 'accessdate', {} );
-- docs
appendSnaks( claims, 'P1545', data, 'docNumber', {} );
-- other
appendSnaks( claims, 'P31', data, 'type', {} );
appendSnaks( claims, 'P818', data, 'arxiv', {} );
appendSnaks( claims, 'P356', data, 'doi', {} );
-- JSTOR
appendSnaks( claims, 'P888', data, 'url', { format = function( id ) return 'http://www.jstor.org/stable/' .. id end } );
return src;
end
function updateWithRef( reference, src )
-- specified
if ( reference.snaks.P662 ) then
local cid = reference.snaks.P662[1].datavalue.value;
src.code = src.code .. '-cid:' .. cid;
src.title = 'Compound Summary for: CID ' .. cid;
src.url = 'http://pubchem.ncbi.nlm.nih.gov/summary/summary.cgi?cid=' .. cid;
src.publication = { id = 'Q278487', label = 'PubChem' };
end
populateDataFromClaims( nil, reference.snaks, src);
return src;
end
function p.renderSource( frame )
p.currentFrame = frame;
local arg = frame.args[1];
local refAnchor = frame.args['ref'];
local refAnchorYear = frame.args['ref-year'];
local args = {};
args.refAnchor = frame.args['ref'];
args.refAnchorYear = frame.args['ref-year'];
args.part = frame.args['part'];
args.pages = frame.args['pages'];
return p.renderSourceImpl( mw.text.trim( arg ), args );
end
function copyArgsToSnaks( args, snaks )
if ( not isEmpty( args.part ) ) then snaks.P958 = { toStringSnak( 'P958', tostring( args.part ) ) } end
if ( not isEmpty( args.pages ) ) then snaks.P304 = { toStringSnak( 'P304', tostring( args.pages ) ) } end
if ( not isEmpty( args.issue ) ) then snaks.P433 = { toStringSnak( 'P433', tostring( args.issue ) ) } end
if ( not isEmpty( args.volume ) ) then snaks.P478 = { toStringSnak( 'P478', tostring( args.volume ) ) } end
if ( not isEmpty( args.url ) ) then snaks.P953 = { toUrlSnak( 'P953', tostring( args.url ) ) } end
end
function p.renderSourceImpl( entityId, args )
args = args or {};
local snaks = {};
snaks.P248 = { toWikibaseEntityIdSnak( 'P248', entityId ) };
copyArgsToSnaks( args, snaks );
local rendered = renderReferenceImpl( mw.wikibase.getEntity(), { snaks = snaks }, args.refAnchor, args.refAnchorYear );
if ( rendered ) then return rendered.text end;
end
function p.renderReference( frame, currentEntity, reference )
p.currentFrame = frame;
-- template call
if ( frame and not currentEntity and not reference ) then
local args = frame.args;
if ( #frame.args == 0 ) then
args = frame:getParent().args;
end
local snaks = {};
if ( args[1] ) then
snaks.P248 = { toWikibaseEntityIdSnak( "P248", args[1] ) };
end
copyArgsToSnaks( args, snaks );
currentEntity = mw.wikibase.getEntity();
reference = { snaks = snaks };
end
local rendered = renderReferenceImpl( currentEntity, reference );
if ( not rendered ) then
return '';
end
local result;
local code = rendered.code or mw.text.encode( rendered.text );
result = frame:extensionTag( 'ref', rendered.text, {name = code} ) .. '[[К:Википедия:Статьи с источниками из Викиданных]]';
return result;
end
function renderReferenceImpl( currentEntity, reference, refAnchor, refAnchorYear )
if ( not reference.snaks ) then
return nil;
end
-- контекст, содержит также кеш элементов
local context = {
cache = {},
}
-- данные в простом формате, согласованном с модулями формирования библиографического описания
local data = {};
local entityId, sourceEntity;
if ( reference and reference.snaks and reference.snaks.P248 ) then
for _, snak in pairs ( reference.snaks.P248 ) do
if ( snak.datavalue ) then
entityId = 'Q' .. snak.datavalue.value["numeric-id"];
sourceEntity = getEntity( context, entityId );
data.code = entityId;
data.entityId = entityId;
break;
end
end
end
updateWithRef( reference, data );
-- update ref name with ref-specific properties
if ( data.code ) then
if ( data.part ) then data.code = data.code .. '-' .. getSingle( data.part ) end
if ( data.pages ) then data.code = data.code .. '-' .. getSingle( data.pages ) end
if ( data.volume ) then data.code = data.code .. '-' .. getSingle( data.volume ) end
if ( data.issue ) then data.code = data.code .. '-' .. getSingle( data.issue ) end
if ( data.url ) then data.code = data.code .. '-' .. getSingle( data.url ) end
end
expandSpecials( currentEntity, reference, data );
if ( sourceEntity ) then
populateSourceDataImpl( sourceEntity, data );
end
if ( not data.publication and data.described ) then
expandDescribed( context, sourceEntity, data );
else
if ( data.publication ) then expandPublication( context, sourceEntity, data ); end
end
if ( next( data ) == nil ) then
return nil;
end
local rendered;
if ( p.short ) then
rendered = renderShortReference( data );
if ( mw.ustring.len( rendered.text ) == 0 ) then
return nil;
end
else
rendered = renderSource( context, data );
if ( mw.ustring.len( rendered.text ) == 0 ) then
return nil;
end
if ( refAnchor ) then
local anchorValue = 'CITEREF' .. refAnchor .. ( coalesce( refAnchorYear, data.year ) or '' );
rendered.text = '<span class="citation" id="' .. mw.uri.anchorEncode( anchorValue ) .. '">' .. rendered.text .. '</span>';
end
end
return rendered;
end
function getNormativeTitle( entity )
if ( not entity or not entity.claims or not entity.claims.P31 ) then
return;
end
for _, claim in pairs( entity.claims.P31 ) do
if ( claim and claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value["numeric-id"] ) then
local classId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
local title = NORMATIVE_DOCUMENTS[ classId ];
if ( title ) then
return title;
end
end
end
return;
end
local LANG_CACHE = {
Q150 = 'fr',
Q188 = 'de',
Q1321 = 'es',
Q1860 = 'en',
Q652 = 'it',
Q7737 = 'ru',
}
function getLangCode( langEntityId )
if ( not langEntityId ) then
return;
end
-- small optimization
local cached = LANG_CACHE[ langEntityId ];
if ( cached ) then return cached; end
local langEntity = mw.wikibase.getEntity( langEntityId );
if ( not langEntity ) then
mw.log( '[getLangCode] Missing entity ' .. langEntityId );
else
if ( langEntity.claims and langEntity.claims.P424 ) then
for _, claim in pairs( langEntity.claims.P424 ) do
if ( claim
and claim.mainsnak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.value ) then
return '' .. claim.mainsnak.datavalue.value;
end
end
end
end
return;
end
function preprocessPlaces( data, lang )
if ( not data.place ) then
return;
end;
local newPlaces = {};
for index, place in pairs( data.place ) do
if ( place.id ) then
local newPlaceStr = getPlaceName(lang, place.id)
if ( newPlaceStr ) then
newPlaces[index] = newPlaceStr;
else
newPlaces[index] = place;
end
else
newPlaces[index] = place;
end
end
data.place = newPlaces;
end
function getPlaceName( lang, placeId )
-- ГОСТ Р 7.0.12—2011
if ( lang == 'ru' ) then
if ( placeId == 'Q649' ) then return toTextWithTip('М.', 'Москва'); end
if ( placeId == 'Q656' ) then return toTextWithTip('СПб.', 'Санкт-Петербург'); end
if ( placeId == 'Q891' ) then return toTextWithTip('Н. Новгород', 'Нижний Новгород'); end
if ( placeId == 'Q908' ) then return toTextWithTip('Ростов н/Д.', 'Ростов-на-Дону'); end
end
return nil;
end
function toTextWithTip( text, tip )
return '<span title="' .. tip .. '" style="border-bottom: 1px dotted; cursor: help; white-space: nowrap">' .. text .. '</span>';
end
return p;