Модуль:Wikidata: юрамалар арасында аерма

Контент бетерелгән Контент өстәлгән
Takhirgeran Umar (бәхәс | кертем)
Төзәтмә аңлатмасы юк
Takhirgeran Umar (бәхәс | кертем)
Төзәтмә аңлатмасы юк
Тамга: кулдан кире кайтару
Юл номеры - 1:
-- vim: set noexpandtab ft=lua ts=4 sw=4:
-- settings, may differ from project to project
require('Module:No globals')
local fileDefaultSize = '267x400px';
local outputReferences = true;
 
local p = {}
-- sources that shall be omitted if any preffered sources exists
local deprecatedSourcesdebug = {false
Q36578 = true, -- Gemeinsame Normdatei
Q63056 = true, -- Find a Grave
Q1798125 = true, -- LIBRIS
Q15222191 = true, -- BNF
Q15241312 = true, -- Freebase
Q29861311 = true, -- SNAC
Q86999151 = true, -- WeChangEd
Q523660 = true, -- International Music Score Library Project by https://ru.wikipedia.org/?diff=107090748
};
 
-- Ссылки на используемые модули, которые потребуются в 99% случаев загрузки страниц (чтобы иметь на виду при переименовании)
local moduleSources = require( 'Module:Sources' )
local WDS = require( 'Module:WikidataSelectors' );
 
------------------------------------------------------------------------------
-- Константы
-- module local variables and functions
local contentLanguageCode = mw.getContentLanguage():getCode();
 
local pwiki = {};
{
local config = nil;
langcode = mw.language.getContentLanguage().code
}
 
-- internationalisation
local formatDatavalue, formatEntityId, formatRefs, formatSnak, formatStatement,
local i18n =
formatStatementDefault, formatProperty, getSourcingCircumstances,
{
getPropertyDatatype, getPropertyParams, throwError, toBoolean;
["errors"] =
{
["property-not-found"] = "Property not found.",
["entity-not-found"] = "Wikidata entity not found.",
["unknown-claim-type"] = "Unknown claim type.",
["unknown-entity-type"] = "Unknown entity type.",
["qualifier-not-found"] = "Qualifier not found.",
["site-not-found"] = "Wikimedia project not found.",
["unknown-datetime-format"] = "Unknown datetime format.",
["local-article-not-found"] = "Article is not yet available in this wiki."
},
["datetime"] =
{
-- $1 is a placeholder for the actual number
[0] = "$1 billion years", -- precision: billion years
[1] = "$100 million years", -- precision: hundred million years
[2] = "$10 million years", -- precision: ten million years
[3] = "$1 million years", -- precision: million years
[4] = "$100,000 years", -- precision: hundred thousand years
[5] = "$10,000 years", -- precision: ten thousand years
[6] = "$1 millennium", -- precision: millennium
[7] = "$1 century", -- precision: century
[8] = "$1s", -- precision: decade
-- the following use the format of #time parser function
[9] = "Y", -- precision: year,
[10] = "F Y", -- precision: month
[11] = "F j, Y", -- precision: day
[12] = "F j, Y ga", -- precision: hour
[13] = "F j, Y g:ia", -- precision: minute
[14] = "F j, Y g:i:sa", -- precision: second
["beforenow"] = "$1 BCE", -- how to format negative numbers for precisions 0 to 5
["afternow"] = "$1 CE", -- how to format positive numbers for precisions 0 to 5
["bc"] = '$1 "BCE"', -- how print negative years
["ad"] = "$1", -- how print positive years
-- the following are for function getDateValue() and getQualifierDateValue()
["default-format"] = "dmy", -- default value of the #3 (getDateValue) or
-- #4 (getQualifierDateValue) argument
["default-addon"] = "BC", -- default value of the #4 (getDateValue) or
-- #5 (getQualifierDateValue) argument
["prefix-addon"] = false, -- set to true for languages put "BC" in front of the
-- datetime string; or the addon will be suffixed
["addon-sep"] = " ", -- separator between datetime string and addon (or inverse)
["format"] = -- options of the 3rd argument
{
["mdy"] = "F j, Y",
["my"] = "F Y",
["y"] = "Y",
["dmy"] = "j F Y",
["ymd"] = "Y-m-d",
["ym"] = "Y-m"
}
},
["monolingualtext"] = '<span lang="%language">%text</span>',
["warnDump"] = "[[Category:Called function 'Dump' from module Wikidata]]",
["ordinal"] =
{
[1] = "st",
[2] = "nd",
[3] = "rd",
["default"] = "th"
}
}
 
--require("Module:i18n").loadI18n("Module:Wikidata/i18n", i18n)
local function copyTo( obj, target, skipEmpty )
-- got idea from [[:w:Module:Wd]]
for k, v in pairs( obj ) do
iflocal skipEmptymodule_title; ~=if true... or ( v ~== nil and v ~= '' ) then
module_title = mw.getCurrentFrame():getTitle()
target[k] = v;
else
end
module_title = ...
end
return target;
end
require('Module:i18n').loadI18n(module_title..'/i18n', i18n)
 
-- this function needs to be internationalised along with the above:
local function min( prev, next )
-- takes cardinal numer as a numeric and returns the ordinal as a string
if ( prev == nil ) then return next;
-- we need three exceptions in English for 1st, 2nd, 3rd, 21st, .. 31st, etc.
elseif ( prev > next ) then return next;
local function makeOrdinal (cardinal)
else return prev; end
local ordsuffix = i18n.ordinal.default
if cardinal % 10 == 1 then
ordsuffix = i18n.ordinal[1]
elseif cardinal % 10 == 2 then
ordsuffix = i18n.ordinal[2]
elseif cardinal % 10 == 3 then
ordsuffix = i18n.ordinal[3]
end
-- In English, 1, 21, 31, etc. use 'st', but 11, 111, etc. use 'th'
-- similarly for 12 and 13, etc.
if (cardinal % 100 == 11) or (cardinal % 100 == 12) or (cardinal % 100 == 13) then
ordsuffix = i18n.ordinal.default
end
return tostring(cardinal) .. ordsuffix
end
 
local function maxprintError( prev, next code)
return '<span class="error">' .. (i18n.errors[code] or code) .. '</span>'
if ( prev == nil ) then return next;
elseif ( prev < next ) then return next;
else return prev; end
end
local function parseDateFormat(f, timestamp, addon, prefix_addon, addon_sep)
 
local year_suffix
local function getConfig( section, code )
local tstr = ""
if config == nil then
local lang_obj = mw.language.new(wiki.langcode)
config = require( 'Module:Wikidata/config' );
local f_parts = mw.text.split(f, 'Y', true)
end;
for idx, f_part in pairs(f_parts) do
if not config then
configyear_suffix = {};''
if string.match(f_part, "x[mijkot]$") then
-- for non-Gregorian year
f_part = f_part .. 'Y'
elseif idx < #f_parts then
-- supress leading zeros in year
year_suffix = lang_obj:formatDate('Y', timestamp)
year_suffix = string.gsub(year_suffix, '^0+', '', 1)
end
tstr = tstr .. lang_obj:formatDate(f_part, timestamp) .. year_suffix
end
if addon ~= "" and prefix_addon then
 
return addon .. addon_sep .. tstr
if not section then
elseif addon ~= "" then
return config;
return tstr .. addon_sep .. addon
end
else
if not code then
return config[ section ] or {};tstr
end
 
if not config[ section ] then
return nil;
end
return config[ section ][ code ];
end
local function parseDateValue(timestamp, date_format, date_addon)
local prefix_addon = i18n["datetime"]["prefix-addon"]
local addon_sep = i18n["datetime"]["addon-sep"]
local addon = ""
 
-- check for negative date
local function getCategoryByCode( code )
if string.sub(timestamp, 1, 1) == '-' then
local value = getConfig( 'categories', code );
timestamp = '+' .. string.sub(timestamp, 2)
if not value or value == '' then
addon = date_addon
return '';
end
local _date_format = i18n["datetime"]["format"][date_format]
return '[[Category:' .. value .. ']]';
if _date_format ~= nil then
end
return parseDateFormat(_date_format, timestamp, addon, prefix_addon, addon_sep)
 
else
local function splitISO8601(str)
return printError("unknown-datetime-format")
if 'table' == type(str) then
if str.args and str.args[1] then
str = '' .. str.args[1]
else
return 'unknown argument type: ' .. type( str ) .. ': ' .. table.tostring( str )
end
end
local Y, M, D = (function(str)
local pattern = "(%-?%d+)%-(%d+)%-(%d+)T"
local Y, M, D = mw.ustring.match( str, pattern )
return tonumber(Y), tonumber(M), tonumber(D)
end) (str);
local h, m, s = (function(str)
local pattern = "T(%d+):(%d+):(%d+)%Z";
local H, M, S = mw.ustring.match( str, pattern);
return tonumber(H), tonumber(M), tonumber(S);
end) (str);
local oh,om = ( function(str)
if str:sub(-1)=="Z" then return 0,0 end; -- ends with Z, Zulu time
-- matches ±hh:mm, ±hhmm or ±hh; else returns nils
local pattern = "([-+])(%d%d):?(%d?%d?)$";
local sign, oh, om = mw.ustring.match( str, pattern);
sign, oh, om = sign or "+", oh or "00", om or "00";
return tonumber(sign .. oh), tonumber(sign .. om);
end )(str)
return {year=Y, month=M, day=D, hour=(h+oh), min=(m+om), sec=s};
end
 
-- This local function combines the year/month/day/BC/BCE handling of parseDateValue{}
local function parseTimeBoundaries( time, precision )
-- with the millennium/century/decade handling of formatDate()
local s = splitISO8601( time );
local function parseDateFull(timestamp, precision, date_format, date_addon)
if (not s) then return nil; end
local prefix_addon = i18n["datetime"]["prefix-addon"]
local addon_sep = i18n["datetime"]["addon-sep"]
local addon = ""
 
-- check for negative date
if ( precision >= 0 and precision <= 8 ) then
if string.sub(timestamp, 1, 1) == '-' then
local powers = { 1000000000 , 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10 }
timestamp = '+' .. string.sub(timestamp, 2)
local power = powers[ precision + 1 ];
addon = date_addon
local left = s.year - ( s.year % power );
return { tonumber(os.time( {year=left, month=1, day=1, hour=0, min=0, sec=0} )) * 1000,
tonumber(os.time( {year=left + power - 1, month=12, day=31, hour=29, min=59, sec=58} )) * 1000 + 1999 };
end
 
-- get the next four characters after the + (should be the year now in all cases)
if ( precision == 9 ) then
-- ok, so this is dirty, but let's get it working first
return { tonumber(os.time( {year=s.year, month=1, day=1, hour=0, min=0, sec=0} )) * 1000,
local intyear = tonumber(string.sub(timestamp, 2, 5))
tonumber(os.time( {year=s.year, month=12, day=31, hour=23, min=59, sec=58} )) * 1000 + 1999 };
if intyear == 0 and precision <= 9 then
return ""
end
 
if (-- precision ==is 10000 10years )or thenmore
if precision <= 5 then
local lastDays = {31, 28.25, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
local lastDayfactor = lastDays[s.month];10 ^ ((5 - precision) + 4)
local y2 = math.ceil(math.abs(intyear) / factor)
return { tonumber(os.time( {year=s.year, month=s.month, day=1, hour=0, min=0, sec=0} )) * 1000,
local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2))
tonumber(os.time( {year=s.year, month=s.month, day=lastDay, hour=23, min=59, sec=58} )) * 1000 + 1999 };
if addon ~= "" then
-- negative date
relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
else
relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
end
return relative
end
 
if (-- precision ==is 11decades (8), thencenturies (7) and millennia (6)
local era, card
return { tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=0, min=0, sec=0} )) * 1000,
if precision == 6 then
tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=23, min=59, sec=58} )) * 1000 + 1999 };
card = math.floor((intyear - 1) / 1000) + 1
era = mw.ustring.gsub(i18n.datetime[6], "$1", makeOrdinal(card))
end
if precision == 7 then
 
card = math.floor((intyear - 1) / 100) + 1
if ( precision == 12 ) then
era = mw.ustring.gsub(i18n.datetime[7], "$1", makeOrdinal(card))
return { tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=s.hour, min=0, sec=0} )) * 1000,
tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=s.hour, min=59, sec=58} )) * 1000 + 1999 };
end
if precision == 8 then
 
era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(intyear) / 10) * 10))
if ( precision == 13 ) then
end
return { tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=0} )) * 1000,
if era then
tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=58} )) * 1000 + 1999 };
if addon ~= "" then
era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era)
else
era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era)
end
return era
end
 
local _date_format = i18n["datetime"]["format"][date_format]
if ( precision == 14 ) then
if _date_format ~= nil then
local t = tonumber(os.time( {year=s.year, month=s.month, day=s.day, hour=s.hour, min=s.min, sec=0} ) );
-- check for precision is year and override supplied date_format
return { t * 1000, t * 1000 + 999 };
if precision == 9 then
_date_format = i18n["datetime"][9]
end
return parseDateFormat(_date_format, timestamp, addon, prefix_addon, addon_sep)
else
return printError("unknown-datetime-format")
end
 
error('Unsupported precision: ' .. precision );
end
 
-- the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
--[[
-- use these as the second parameter and this function instead of the built-in "pairs" function
Преобразует строку в булевое значение
-- to iterate over all qualifiers and snaks in the intended order.
local function orderedpairs(array, order)
if not order then return pairs(array) end
 
-- return iterator function
Принимает: строковое значение (может отсутствовать)
local i = 0
Возвращает: булевое значение true или false, если получается распознать значение, или defaultValue во всех остальных случаях
return function()
]]
i = i + 1
local function toBoolean( valueToParse, defaultValue )
if ( valueToParse ~= nil )order[i] then
return order[i], array[order[i]]
if valueToParse == false or valueToParse == '' or valueToParse == 'false' or valueToParse == '0' then
return false
end
return true
end
return defaultValue;
end
 
-- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
--[[
local function normalizeDate(date)
Обрачивает отформатированное значение в тег
date = mw.text.trim(date, "+")
-- extract year
Принимает: строковое значение, строку с атрибутами (может отсутствовать)
local yearstr = mw.ustring.match(date, "^\-?%d+")
Возвращает: строковое значение, значения с блочными тегами остаются блоком, текст встраиваем в строку
local year = tonumber(yearstr)
]]
-- remove leading zeros of year
local function wrapFormatProperty( value, attributes )
return year .. mw.ustring.sub(date, #yearstr + 1), year
local tagName = 'span';
local spacer = '';
if ( string.match( value, '\n' )
or string.match( value, '<t[dhr][ >]' )
or string.match( value, '<div[ >]' )
or string.find( value, 'UNIQ%-%-imagemap' ) ) then
tagName = 'div';
spacer = '\n'
end
return '<' .. tagName .. ' ' .. ( attributes or '' ) .. '>' .. spacer .. value .. '</' .. tagName .. '>';
end
 
local function formatDate(date, precision, timezone)
--[[
precision = precision or 11
Функция для получения сущности (еntity) для текущей страницы
local date, year = normalizeDate(date)
Подробнее о сущностях см. d:Wikidata:Glossary/ru
if year == 0 and precision <= 9 then return "" end
 
-- precision is 10000 years or more
Принимает: строковый индентификатор (типа P18, Q42)
if precision <= 5 then
Возвращает: объект таблицу, элементы которой индексируются с нуля
local factor = 10 ^ ((5 - precision) + 4)
]]
local functiony2 getEntityFromId= math.ceil(math.abs(year) id/ factor)
local relative = mw.ustring.gsub(i18n.datetime[precision], "$1", tostring(y2))
local entity;
if year < 0 then
local wbStatus;
relative = mw.ustring.gsub(i18n.datetime.beforenow, "$1", relative)
else
relative = mw.ustring.gsub(i18n.datetime.afternow, "$1", relative)
end
return relative
end
 
-- precision is decades, centuries and millennia
if id then
local era
wbStatus, entity = pcall( mw.wikibase.getEntityObject, id )
if precision == 6 then era = mw.ustring.gsub(i18n.datetime[6], "$1", tostring(math.floor((math.abs(year) - 1) / 1000) + 1)) end
else
if precision == 7 then era = mw.ustring.gsub(i18n.datetime[7], "$1", tostring(math.floor((math.abs(year) - 1) / 100) + 1)) end
wbStatus, entity = pcall( mw.wikibase.getEntityObject );
if precision == 8 then era = mw.ustring.gsub(i18n.datetime[8], "$1", tostring(math.floor(math.abs(year) / 10) * 10)) end
if era then
if year < 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.bc, '"', ""), "$1", era)
elseif year > 0 then era = mw.ustring.gsub(mw.ustring.gsub(i18n.datetime.ad, '"', ""), "$1", era) end
return era
end
 
-- precision is year
return entity;
if precision == 9 then
end
return year
 
--[[
Внутрення функция для формирования сообщения об ошибке
 
Принимает: ключ элемента в таблице config.errors (например entity-not-found)
Возвращает: строку сообщения
]]
local function throwError( key )
error( getConfig( 'errors', key ) );
end
 
--[[
Функция для получения идентификатора сущностей
 
Принимает: объект таблицу сущности
Возвращает: строковый индентификатор (типа P18, Q42)
]]
local function getEntityIdFromValue( value )
local prefix = ''
if value['entity-type'] == 'item' then
prefix = 'Q'
elseif value['entity-type'] == 'property' then
prefix = 'P'
else
throwError( 'unknown-entity-type' )
end
return prefix .. value['numeric-id']
end
 
-- precision is less than years
-- проверка на наличие специилизированной функции в опциях
if precision > 9 then
local function getUserFunction( options, prefix, defaultFunction )
--[[ the following code replaces the UTC suffix with the given negated timezone to convert the global time to the given local time
-- проверка на указание специализированных обработчиков в параметрах,
timezone = tonumber(timezone)
-- переданных при вызове
if timezone and timezone ~= 0 then
if options[ prefix .. '-module' ] or options[ prefix .. '-function' ] then
timezone = -timezone
-- проверка на пустые строки в параметрах или их отсутствие
timezone = string.format("%.2d%.2d", timezone / 60, timezone % 60)
if not options[ prefix .. '-module' ] or not options[ prefix .. '-function' ] then
throwError(if timezone[1] ~= 'unknown-' ..then prefixtimezone = "+" .. '-module'timezone );end
date = mw.text.trim(date, "Z") .. " " .. timezone
end
]]--
-- динамическая загруза модуля с обработчиком указанным в параметре
 
local formatter = require( 'Module:' .. options[ prefix .. '-module' ] );
local formatstr = i18n.datetime[precision]
if formatter == nil then
if year == 0 then formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], "")
throwError( prefix .. '-module-not-found' )
elseif year < 0 then
end
-- Mediawiki formatDate doesn't support negative years
local fun = formatter[ options[ prefix .. '-function' ] ]
date = mw.ustring.sub(date, 2)
if fun == nil then
formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.bc, "$1", i18n.datetime[9]))
throwError( prefix .. '-function-not-found' )
elseif year > 0 and i18n.datetime.ad ~= "$1" then
formatstr = mw.ustring.gsub(formatstr, i18n.datetime[9], mw.ustring.gsub(i18n.datetime.ad, "$1", i18n.datetime[9]))
end
return mw.language.new(wiki.langcode):formatDate(formatstr, date)
return fun;
end
 
return defaultFunction;
end
 
local function printDatavalueEntity(data, parameter)
-- Выбирает свойства по property id, дополнительно фильтруя их по рангу
-- data fields: entity-type [string], numeric-id [int, Wikidata id]
local function selectClaims( context, options, propertySelector )
local id
if ( not context ) then error( 'context not specified' ); end;
if ( not options ) then error( 'options not specified' ); end;
if ( not options.entity ) then error( 'options.entity is missing' ); end;
if ( not propertySelector ) then error( 'propertySelector not specified' ); end;
 
result = WDS.filter( options.entity.claims, propertySelector );
 
if data["entity-type"] == "item" then id = "Q" .. data["numeric-id"]
if ( not result or #result == 0 ) then
elseif data["entity-type"] == "property" then id = "P" .. data["numeric-id"]
return nil;
else return printError("unknown-entity-type")
end
 
if parameter then
if options.limit and options.limit ~= '' and options.limit ~= '-' then
if parameter == "link" then
local limit = tonumber( options.limit, 10 );
local linkTarget = mw.wikibase.sitelink(id)
while #result > limit do
local linkName = mw.wikibase.label(id)
table.remove( result );
if linkTarget then
-- if there is a local Wikipedia article link to it using the label or the article title
return "[[" .. linkTarget .. "|" .. (linkName or linkTarget) .. "]]"
else
-- if there is no local Wikipedia article output the label or link to the Wikidata object to let the user input a proper label
if linkName then return linkName else return "[[:d:" .. id .. "|" .. id .. "]]" end
end
else
return data[parameter]
end
else
return mw.wikibase.label(id) or id
end
end
 
local function printDatavalueTime(data, parameter)
return result;
-- data fields: time [ISO 8601 time], timezone [int in minutes], before [int], after [int], precision [int], calendarmodel [wikidata URI]
-- precision: 0 - billion years, 1 - hundred million years, ..., 6 - millennia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
-- calendarmodel: e.g. http://www.wikidata.org/entity/Q1985727 for the proleptic Gregorian calendar or http://www.wikidata.org/wiki/Q11184 for the Julian calendar]
if parameter then
if parameter == "calendarmodel" then data.calendarmodel = mw.ustring.match(data.calendarmodel, "Q%d+") -- extract entity id from the calendar model URI
elseif parameter == "time" then data.time = normalizeDate(data.time) end
return data[parameter]
else
return formatDate(data.time, data.precision, data.timezone)
end
end
 
local function printDatavalueMonolingualText(data, parameter)
--[[
-- data fields: language [string], text [string]
Функция для получения значения свойства элемента в заданный момент времени.
if parameter then
 
return data[parameter]
Принимает: контекст, элемент, временные границы, таблица ID свойства
else
Возвращает: таблицу соответствующих значений свойства
local result = mw.ustring.gsub(mw.ustring.gsub(i18n.monolingualtext, "%%language", data["language"]), "%%text", data["text"])
]]
return result
local function getPropertyInBoundaries( context, entityId, boundaries, propertyIds, selectors )
if (type(entityId) ~= 'string') then error('type of entityId argument expected string, but was ' .. type(entityId)); end
 
local results = {};
 
if not propertyIds or #propertyIds == 0 then
return results;
end
end
 
local function findClaims(entity, property)
for _, propertyId in ipairs( propertyIds ) do
if not property or not entity or not entity.claims then return end
local selector = selectors[_];
local propertyClaims = mw.wikibase.getAllStatements( entityId, propertyId );
local fakeAllClaims = {};
fakeAllClaims[propertyId] = propertyClaims;
local filteredClaims = WDS.filter( fakeAllClaims, selector .. '[rank:preferred, rank:normal]' );
if filteredClaims then
for _, claim in pairs( filteredClaims ) do
if not boundaries then
table.insert( results, claim.mainsnak );
else
local startBoundaries = p.getTimeBoundariesFromQualifier( context.frame, context, claim, 'P580' );
local endBoundaries = p.getTimeBoundariesFromQualifier( context.frame, context, claim, 'P582' );
 
if mw.ustring.match(property, "^P%d+$") then
if ( (startBoundaries == nil or ( startBoundaries[2] <= boundaries[1]))
-- if the property is given by an id (P..) access the claim list by this id
and (endBoundaries == nil or ( endBoundaries[1] >= boundaries[2]))) then
return entity.claims[property]
table.insert( results, claim.mainsnak );
else
end
property = mw.wikibase.resolvePropertyId(property)
end
if not property then return end
end
end
 
return entity.claims[property]
if #results > 0 then
break;
end
end
 
return results;
end
 
local function getSnakValue(snak, parameter)
--[[
if snak.snaktype == "value" then
TODO
-- call the respective snak parser
]]
if snak.datavalue.type == "string" then return snak.datavalue.value
function p.getTimeBoundariesFromQualifier( frame, context, statement, qualifierId )
elseif snak.datavalue.type == "globecoordinate" then return printDatavalueCoordinate(snak.datavalue.value, parameter)
-- only support exact date so far, but need improvment
elseif snak.datavalue.type == "quantity" then return printDatavalueQuantity(snak.datavalue.value, parameter)
local left = nil;
elseif snak.datavalue.type == "time" then return printDatavalueTime(snak.datavalue.value, parameter)
local right = nil;
elseif snak.datavalue.type == "wikibase-entityid" then return printDatavalueEntity(snak.datavalue.value, parameter)
if ( statement.qualifiers and statement.qualifiers[qualifierId] ) then
elseif snak.datavalue.type == "monolingualtext" then return printDatavalueMonolingualText(snak.datavalue.value, parameter)
for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do
local boundaries = context.parseTimeBoundariesFromSnak( qualifier );
if ( not boundaries ) then return nil; end
left = min( left, boundaries[1] );
right = max( right, boundaries[2] );
end
end
return mw.wikibase.renderSnak(snak)
 
if ( not left or not right ) then
return nil;
end
 
return { left, right };
end
 
local function getQualifierSnak(claim, qualifierId)
--[[
-- a "snak" is Wikidata terminology for a typed key/value pair
TODO
-- a claim consists of a main snak holding the main information of this claim,
]]
-- as well as a list of attribute snaks and a list of references snaks
function p.getTimeBoundariesFromQualifiers( frame, context, statement, qualifierIds )
if not qualifierIdsqualifierId then
-- search the attribute snak with the given qualifier as key
qualifierIds = { 'P582', 'P580', 'P585' };
if claim.qualifiers then
end
local qualifier = claim.qualifiers[qualifierId]
 
if qualifier then return qualifier[1] end
for _, qualifierId in ipairs( qualifierIds ) do
local result = p.getTimeBoundariesFromQualifier( frame, context, statement, qualifierId );
if result then
return result;
end
return nil, printError("qualifier-not-found")
else
-- otherwise return the main snak
return claim.mainsnak
end
 
return nil;
end
 
local function getValueOfClaim(claim, qualifierId, parameter)
local CONTENT_LANGUAGE_CODE = mw.language.getContentLanguage():getCode();
local error
local getLabelWithLang_DEFAULT_PROPERTIES = { "P1813", "P1448", "P1705" };
local snak
local getLabelWithLang_DEFAULT_SELECTORS = {
snak, error = getQualifierSnak(claim, qualifierId)
'P1813[language:' .. CONTENT_LANGUAGE_CODE .. ']',
if snak then
'P1448[language:' .. CONTENT_LANGUAGE_CODE .. ']',
return getSnakValue(snak, parameter)
'P1705[language:' .. CONTENT_LANGUAGE_CODE .. ']'
else
};
return nil, error
 
--[[
Функция для получения метки элемента в заданный момент времени.
 
Принимает: контекст, элемент, временные границы
Возвращает: текстовую метку элемента, язык метки
]]
local function getLabelWithLang( context, options, entityId, boundaries, propertyIds, selectors )
if (type(entityId) ~= 'string') then error('type of entityId argument expected string, but was ' .. type(entityId)); end
if not entityId then
return nil;
end
end
 
local function getReferences(frame, claim)
local langCode = CONTENT_LANGUAGE_CODE;
local result = ""
 
-- traverse through all references
-- name from label
for ref in pairs(claim.references or {}) do
local label = nil;
local refparts
if ( options.text and options.text ~= '' ) then
-- traverse through all parts of the current reference
label = options.text;
for snakkey, snakval in orderedpairs(claim.references[ref].snaks or {}, claim.references[ref]["snaks-order"]) do
else
if refparts then refparts = refparts .. ", " else refparts = "" end
if not propertyIds then
-- output the label of the property of the reference part, e.g. "imported from" for P143
propertyIds = getLabelWithLang_DEFAULT_PROPERTIES;
refparts = refparts .. tostring(mw.wikibase.label(snakkey)) .. ": "
selectors = getLabelWithLang_DEFAULT_SELECTORS;
-- output all values of this reference part, e.g. "German Wikipedia" and "English Wikipedia" if the referenced claim was imported from both sites
end
for snakidx = 1, #snakval do
 
if snakidx > 1 then refparts = refparts .. ", " end
-- name from properties
refparts = refparts .. getSnakValue(snakval[snakidx])
local results = getPropertyInBoundaries( context, entityId, boundaries, propertyIds, selectors );
 
for _, result in pairs( results ) do
if result.datavalue and result.datavalue.value then
if result.datavalue.type == 'monolingualtext' and result.datavalue.value.text then
label = result.datavalue.value.text;
langCode = result.datavalue.value.language;
break;
elseif result.datavalue.type == 'string' then
label = result.datavalue.value;
break;
end
end
end
if (not label) then
label, langCode = mw.wikibase.getLabelWithLang( entityId );
if not langCode then
return nil;
end
end
if refparts then result = result .. frame:extensionTag("ref", refparts) end
end
return result
 
return label, langCode;
end
 
local function formatPropertyDefaultparseInput( context, options frame)
local qid = frame.args.qid
if ( not context ) then error( 'context not specified' ); end;
if qid and (#qid not options== 0) then error(qid 'options= not specified' );nil end;
local propertyID = mw.text.trim(frame.args[1] or "")
if ( not options.entity ) then error( 'options.entity missing' ); end;
local input_parm = mw.text.trim(frame.args[2] or "")
 
if input_parm ~= "FETCH_WIKIDATA" then
local claims;
return false, input_parm, nil, nil
if options.property then -- TODO: Почему тут может не быть property?
claims = context.selectClaims( options, options.property );
end
local entity = mw.wikibase.getEntityObject(qid)
if claims == nil then
local claims
return '' --TODO error?
if entity and entity.claims then
claims = entity.claims[propertyID]
if not claims then
return false, "", nil, nil
end
else
return false, "", nil, nil
end
return true, entity, claims, propertyID
 
end
-- Обход всех заявлений утверждения и с накоплением оформленых предпочтительных
local function isType(claims, type)
-- заявлений в таблице
return claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == type
local formattedClaims = {}
end
 
local function getValue(entity, claims, propertyID, delim, labelHook)
for i, claim in ipairs(claims) do
if labelHook == nil then
local formattedStatement = context.formatStatement( options, claim )
labelHook = function (qnumber)
-- здесь может вернуться либо оформленный текст заявления, либо строка ошибки, либо nil
return nil;
if ( formattedStatement and formattedStatement ~= '' ) then
formattedStatement = '<span class="wikidata-claim" data-wikidata-property-id="' .. string.upper( options.property ) .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>'
table.insert( formattedClaims, formattedStatement )
end
end
if isType(claims, "wikibase-entityid") then
 
local out = {}
-- создание текстовой строки со списком оформленых заявлений из таблицы
for k, v in pairs(claims) do
local out = mw.text.listToText( formattedClaims, options.separator, options.conjunction )
local qnumber = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
if out ~= '' then
local sitelink = mw.wikibase.sitelink(qnumber)
if options.before then
local label = labelHook(qnumber) or mw.wikibase.label(qnumber) or qnumber
out = options.before .. out
if sitelink then
end
out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]"
if options.after then
else
out = out .. options.after
out[#out + 1] = "[[:d:" .. qnumber .. "|" .. label .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
end
return table.concat(out, delim)
else
-- just return best values
return entity:formatPropertyValues(propertyID).value
end
 
return out
end
 
------------------------------------------------------------------------------
--[[
-- module global functions
Функция для оформления утверждений (statement)
Подробнее о утверждениях см. d:Wikidata:Glossary/ru
 
if debug then
Принимает: таблицу параметров
function p.inspectI18n(frame)
Возвращает: строку оформленного текста, предназначенного для отображения в статье
local val = i18n
]]
for _, key in pairs(frame.args) do
local function formatProperty( options )
key = mw.text.trim(key)
-- Получение сущности по идентификатору
val = val[key]
local entity = getEntityFromId( options.entityId )
end
if not entity then
return -- throwError( 'entity-not-found' )val
end
-- проверка на присутсвие у сущности заявлений (claim)
-- подробнее о заявлениях см. d:Викиданные:Глоссарий
if (entity.claims == nil) then
return '' --TODO error?
end
end
 
function p.descriptionIn(frame)
-- improve options
local langcode = frame.args[1]
options.frame = g_frame;
local id = frame.args[2]
options.entity = entity;
-- return description of a Wikidata entity in the given language or the default language of this Wikipedia site
options.extends = function( self, newOptions )
return mw.wikibase.getEntityObject(id).descriptions[langcode or wiki.langcode].value
return copyTo( newOptions, copyTo( self, {} ) )
end
 
function p.labelIn(frame)
if ( options.i18n ) then
local langcode = frame.args[1]
options.i18n = copyTo( options.i18n, copyTo( getConfig( 'i18n' ), {} ) );
local id = frame.args[2]
else
-- return label of a Wikidata entity in the given language or the default language of this Wikipedia site
options.i18n = getConfig( 'i18n' );
return mw.wikibase.getEntityObject(id).labels[langcode or wiki.langcode].value
end
 
-- create context
local context = {
entity = options.entity,
formatSnak = formatSnak,
formatPropertyDefault = formatPropertyDefault,
formatStatementDefault = formatStatementDefault }
context.cloneOptions = function( options )
local entity = options.entity;
options.entity = nil;
 
newOptions = mw.clone( options );
options.entity = entity;
newOptions.entity = entity;
newOptions.frame = options.frame; -- На склонированном фрейме frame:expandTemplate()
 
return newOptions;
end;
context.formatProperty = function( options )
local func = getUserFunction( options, 'property', context.formatPropertyDefault );
return func( context, options )
end;
context.formatStatement = function( options, statement ) return formatStatement( context, options, statement ) end;
context.formatSnak = function( options, snak, circumstances ) return formatSnak( context, options, snak, circumstances ) end;
context.formatRefs = function( options, statement ) return formatRefs( context, options, statement ) end;
 
context.parseTimeFromSnak = function( snak )
if ( snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time ) then
return tonumber(os.time( splitISO8601( tostring( snak.datavalue.value.time ) ) ) ) * 1000;
end
return nil;
end
context.parseTimeBoundariesFromSnak = function( snak )
if ( snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time and snak.datavalue.value.precision ) then
return parseTimeBoundaries( snak.datavalue.value.time, snak.datavalue.value.precision );
end
return nil;
end
context.getSourcingCircumstances = function( statement ) return getSourcingCircumstances( statement ) end;
context.selectClaims = function( options, propertyId ) return selectClaims( context, options, propertyId ) end;
 
return context.formatProperty( options );
end
 
-- This is used to get a value, or a comma separated list of them if multiple values exist
--[[
p.getValue = function(frame)
Функция для оформления одного утверждения (statement)
local delimdefault = ", " -- **internationalise later**
 
local delim = frame.args.delimiter or ""
Принимает: объект-таблицу утверждение и таблицу параметров
delim = string.gsub(delim, '"', '')
Возвращает: строку оформленного текста с заявлением (claim)
if #delim == 0 then
]]
delim = delimdefault
function formatStatement( context, options, statement )
if ( not statement ) then
error( 'statement is not specified or nil' );
end
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not statement.type or statement.type ~= 'statement' then
if not go then
throwError( 'unknown-claim-type' )
return errorOrentity
end
return getValue(errorOrentity, claims, propertyID, delim)
 
local functionToCall = getUserFunction( options, 'claim', context.formatStatementDefault );
return functionToCall( context, options, statement );
end
 
-- Same as above, but uses the short name property for label if available.
function getSourcingCircumstances( statement )
p.getValueShortName = function(frame)
if (not statement) then error('statement is not specified') end;
local go, errorOrentity, claims, propertyID = parseInput(frame)
 
if not go then
local circumstances = {};
return errorOrentity
if ( statement.qualifiers
and statement.qualifiers.P1480 ) then
for i, qualifier in pairs( statement.qualifiers.P1480 ) do
if ( qualifier
and qualifier.datavalue
and qualifier.datavalue.type == 'wikibase-entityid'
and qualifier.datavalue.value
and qualifier.datavalue.value['entity-type'] == 'item' ) then
table.insert(circumstances, qualifier.datavalue.value.id)
end
end
end
local entity = errorOrentity
return circumstances;
-- if wiki-linked value output as link if possible
end
local function labelHook (qnumber)
 
local label
--[[
local claimEntity = mw.wikibase.getEntity(qnumber)
Функция для оформления одного утверждения (statement)
if claimEntity ~= nil then
 
if claimEntity.claims.P1813 then
Принимает: объект-таблицу утверждение, таблицу параметров,
for k2, v2 in pairs(claimEntity.claims.P1813) do
объект-функцию оформления внутренних структур утверждения (snak) и
if v2.mainsnak.datavalue.value.language == "en" then
объект-функцию оформления ссылки на источники (reference)
label = v2.mainsnak.datavalue.value.text
Возвращает: строку оформленного текста с заявлением (claim)
end
]]
end
function formatStatementDefault( context, options, statement )
if (not context) then error('context is not specified') end;
if (not options) then error('options is not specified') end;
if (not statement) then error('statement is not specified') end;
 
local circumstances = context.getSourcingCircumstances( statement );
 
options.qualifiers = statement.qualifiers;
 
local result = context.formatSnak( options, statement.mainsnak, circumstances );
if ( options.qualifier and statement.qualifiers and statement.qualifiers[ options.qualifier ] ) then
qualConfig = getPropertyParams( options.qualifier, nil, {})
if options.i18n then qualConfig.i18n = options.i18n end
local qualifierValues = {};
for _, qualifierSnak in pairs( statement.qualifiers[ options.qualifier ] ) do
local snakValue = context.formatSnak( qualConfig, qualifierSnak );
if snakValue and snakValue ~= '' then
table.insert( qualifierValues, snakValue );
end
end
if (label result== andnil resultor label ~== ''"" andthen #qualifierValuesreturn )nil thenend
return label
if qualConfig.invisible then
result = result .. table.concat( qualifierValues, ', ' );
else
result = result .. ' (' .. table.concat( qualifierValues, ', ' ) .. ')';
end
end
end
 
if ( result and result ~= '' and options.references ) then
result = result .. context.formatRefs( options, statement );
end
return getValue(errorOrentity, claims, propertyID, ", ", labelHook);
 
return result;
end
 
-- This is used to get a value, or a comma separated list of them if multiple values exist
--[[
-- from an arbitrary entry by using its QID.
Функция для оформления части утверждения (snak)
-- Use : {{#invoke:Wikidata|getValueFromID|<ID>|<Property>|FETCH_WIKIDATA}}
Подробнее о snak см. d:Викиданные:Глоссарий
-- E.g.: {{#invoke:Wikidata|getValueFromID|Q151973|P26|FETCH_WIKIDATA}} - to fetch value of 'spouse' (P26) from 'Richard Burton' (Q151973)
 
-- Please use sparingly - this is an *expensive call*.
Принимает: таблицу snak объекта (main snak или же snak от квалификатора) и таблицу опций
p.getValueFromID = function(frame)
Возвращает: строку оформленного викитекста
local itemID = mw.text.trim(frame.args[1] or "")
]]
local propertyID = mw.text.trim(frame.args[2] or "")
function formatSnak( context, options, snak, circumstances )
local input_parm = mw.text.trim(frame.args[3] or "")
circumstances = circumstances or {};
if input_parm == "FETCH_WIKIDATA" then
local hash = '';
local entity = mw.wikibase.getEntity(itemID)
local mainSnakClass = '';
local claims
if ( snak.hash ) then
if entity and entity.claims then
hash = ' data-wikidata-hash="' .. snak.hash .. '"';
claims = entity.claims[propertyID]
else
mainSnakClass = ' wikidata-main-snak';
end
 
local before = '<span class="wikidata-snak ' .. mainSnakClass .. '"' .. hash .. '>'
local after = '</span>'
 
if snak.snaktype == 'somevalue' then
if ( options['somevalue'] and options['somevalue'] ~= '' ) then
result = options['somevalue'];
else
result = options.i18n['somevalue'];
end
if claims then
elseif snak.snaktype == 'novalue' then
return getValue(entity, claims, propertyID, ", ")
if ( options['novalue'] and options['novalue'] ~= '' ) then
result = options['novalue'];
else
return ""
result = options.i18n['novalue'];
end
else
elseif snak.snaktype == 'value' then
return input_parm
result = formatDatavalue( context, options, snak.datavalue, snak.datatype );
end
for _, item in pairs(circumstances) do
end
if options.i18n[item] then
local function getQualifier(frame, outputHook)
result = options.i18n[item] .. result;
local propertyID = mw.text.trim(frame.args[1] or "")
local qualifierID = mw.text.trim(frame.args[2] or "")
local input_parm = mw.text.trim(frame.args[3] or "")
if input_parm == "FETCH_WIKIDATA" then
local entity = mw.wikibase.getEntityObject()
if entity.claims[propertyID] ~= nil then
local out = {}
for k, v in pairs(entity.claims[propertyID]) do
for k2, v2 in pairs(v.qualifiers[qualifierID]) do
if v2.snaktype == 'value' then
out[#out + 1] = outputHook(v2);
end
end
end
return table.concat(out, ", "), true
else
return "", false
end
else
return input_parm, false
throwError( 'unknown-snak-type' );
end
end
p.getQualifierValue = function(frame)
if ( not result or result == '' ) then
local function outputValue(value)
return nil;
local qnumber = "Q" .. value.datavalue.value["numeric-id"]
if (mw.wikibase.sitelink(qnumber)) then
return "[[" .. mw.wikibase.sitelink(qnumber) .. "]]"
else
return "[[:d:" .. qnumber .. "|" ..qnumber .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
end
return (getQualifier(frame, outputValue))
end
 
-- This is used to get a value like 'male' (for property p21) which won't be linked and numbers without the thousand separators
return before .. result .. after;
p.getRawValue = function(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
return errorOrentity
end
local entity = errorOrentity
local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
-- if number type: remove thousand separators, bounds and units
if isType(claims, "quantity") then
result = mw.ustring.gsub(result, "(%d),(%d)", "%1%2")
result = mw.ustring.gsub(result, "(%d)±.*", "%1")
end
return result
end
 
-- This is used to get the unit name for the numeric value returned by getRawValue
--[[
p.getUnits = function(frame)
Функция для оформления объектов-значений с географическими координатами
local go, errorOrentity, claims, propertyID = parseInput(frame)
 
if not go then
Принимает: объект-значение и таблицу параметров,
return errorOrentity
Возвращает: строку оформленного текста
]]
local function formatGlobeCoordinate( value, options )
-- проверка на требование в параметрах вызова на возврат сырого значения
if options['subvalue'] == 'latitude' then -- широты
return value['latitude']
elseif options['subvalue'] == 'longitude' then -- долготы
return value['longitude']
elseif options['nocoord'] and options['nocoord'] ~= '' then
-- если передан параметр nocoord, то не выводить координаты
-- обычно это делается при использовании нескольких карточек на странице
return ''
else
-- в противном случае формируются параметры для вызова шаблона {{coord}}
-- нужно дописать в документации шаблона, что он отсюда вызывается, и что
-- любое изменние его парамеров должно быть согласовано с кодом тут
coord_mod = require( "Module:Coordinates" );
local globe = options.globe or ''
if globe == '' and value['globe'] then
globes = require( 'Module:Wikidata/Globes' )
globe = globes[value['globe']] or ''
end
local display = 'inline'
if options.display and options.display ~= '' then
display = options.display
elseif ( options.property:upper() == 'P625' ) then
display = 'title'
end
g_frame.args = {tostring(value['latitude']), tostring(value['longitude']), globe = globe, type = options.type and options.type or '', display = display }
return coord_mod.coord(g_frame)
end
local entity = errorOrentity
local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
if isType(claims, "quantity") then
result = mw.ustring.sub(result, mw.ustring.find(result, " ")+1, -1)
end
return result
end
 
-- This is used to get the unit's QID to use with the numeric value returned by getRawValue
--[[
p.getUnitID = function(frame)
Функция для оформления объектов-значений с файлами с Викисклада
local go, errorOrentity, claims = parseInput(frame)
 
if not go then
Принимает: объект-значение и таблицу параметров,
return errorOrentity
Возвращает: строку оформленного текста
]]
local function formatCommonsMedia( value, options )
local image = value;
 
local caption = '';
if options[ 'caption' ] and options[ 'caption' ] ~= '' then
caption = options[ 'caption' ];
elseif options[ 'description' ] and options[ 'description' ] ~= '' then
caption = options[ 'description' ];
end
local entity = errorOrentity
if caption ~= '' then
local result
caption = wrapFormatProperty( caption, 'class="media-caption" data-wikidata-qualifier-id="P2096" style="display:block;"' );
if isType(claims, "quantity") then
-- get the url for the unit entry on Wikidata:
result = claims[1].mainsnak.datavalue.value.unit
-- and just reurn the last bit from "Q" to the end (which is the QID):
result = mw.ustring.sub(result, mw.ustring.find(result, "Q"), -1)
end
return result
end
 
p.getRawQualifierValue = function(frame)
if not string.find( value, '[%[%]%{%}]' ) and not string.find( value, 'UNIQ%-%-imagemap' ) then
local function outputHook(value)
-- если в value не содержится викикод или imagemap, то викифицируем имя файла
if value.datavalue.value["numeric-id"] then
-- ищем слово imagemap в строке, потому что вставляется плейсхолдер: [[PHAB:T28213]]
return mw.wikibase.label("Q" .. value.datavalue.value["numeric-id"])
image = '[[File:' .. value .. '|frameless';
if options[ 'border' ] and options[ 'border' ] ~= '' then
image = image .. '|border';
end
 
local size = options[ 'size' ];
if size and size ~= '' then
if not string.match( size, 'px$' )
and not string.match( size, 'пкс$' ) -- TODO: использовать перевод для языка вики
then
size = size .. 'px'
end
else
return value.datavalue.value
size = fileDefaultSize;
end
image = image .. '|' .. size;
 
if options[ 'alt' ] and options[ 'alt' ] ~= '' then
image = image .. '|' .. options[ 'alt' ];
end
image = image .. ']]';
 
if caption ~= '' then
image = image .. '<br>' .. caption;
end
 
if options[ 'local_caption' ] and options[ 'local_caption' ] ~= '' then
image = image .. getCategoryByCode( 'media-contains-local-caption' )
end
else
image = image .. caption .. getCategoryByCode( 'media-contains-markup' );
end
local ret, gotData = getQualifier(frame, outputHook)
if gotData then
if options.entity and options.fixdouble then
ret = string.upper(string.sub(ret, 1, 1)) .. string.sub(ret, 2)
local page = mw.title.getCurrentTitle()
local txt = page:getContent()
if txt and txt:match(':' .. value) and mw.title.getCurrentTitle():inNamespace(0) then image = image .. getCategoryByCode( 'media-contains-local-double' ) end
end
return ret
return image
end
 
-- This is used to get a date value for date_of_birth (P569), etc. which won't be linked
--[[
-- Dates and times are stored in ISO 8601 format (sort of).
Fonction for render math formulas
-- At present the local formatDate(date, precision, timezone) function doesn't handle timezone
 
-- So I'll just supply "Z" in the call to formatDate below:
@param string Value.
p.getDateValue = function(frame)
@param table Parameters.
local date_format = mw.text.trim(frame.args[3] or i18n["datetime"]["default-format"])
@return string Formatted string.
local date_addon = mw.text.trim(frame.args[4] or i18n["datetime"]["default-addon"])
]]
local go, errorOrentity, claims = parseInput(frame)
local function formatMath( value, options )
if not go then
return options.frame:extensionTag{ name = 'math', content = value };
return errorOrentity
end
 
--[[
Функция для оформления внешних идентификаторов
 
Принимает: объект-значение и таблицу параметров,
Возвращает: строку оформленного текста
]]
local function formatExternalId( value, options )
local formatter = options.formatter;
 
if not formatter or formatter == '' then
local wbStatus, propertyEntity = pcall( mw.wikibase.getEntity, options.property:upper() )
if wbStatus == true and propertyEntity then
local isGoodFormat = false;
local statements = propertyEntity:getBestStatements( 'P1793' );
for _, statement in pairs( statements ) do
if statement.mainsnak.snaktype == 'value' then
local pattern = mw.ustring.gsub( statement.mainsnak.datavalue.value, '\\', '%' );
pattern = mw.ustring.gsub( pattern, '{%d+,?%d*}', '+' );
if ( string.find( pattern, '|' ) or string.find( pattern, '%)%?' )
or mw.ustring.match( value, '^' .. pattern .. '$' ) ~= nil ) then
isGoodFormat = true;
break;
end
end
end
 
if ( isGoodFormat == true ) then
statements = propertyEntity:getBestStatements( 'P1630' );
for _, statement in pairs( statements ) do
if statement.mainsnak.snaktype == 'value' then
formatter = statement.mainsnak.datavalue.value;
break
end
end
end
end
end
local entity = errorOrentity
 
local out = {}
if formatter and formatter ~= '' then
for k, v in pairs(claims) do
local link = mw.ustring.gsub(
if v.mainsnak.datavalue.type == 'time' then
mw.ustring.gsub( formatter, '$1', value ), '.',
local timestamp = v.mainsnak.datavalue.value.time
{ [' '] = '%20', ['+'] = '%2b' } )
local dateprecision = v.mainsnak.datavalue.value.precision
 
-- A year can be stored like this: "+1872-00-00T00:00:00Z",
local title = options.title
-- which is processed here as if it were the day before "+1872-01-01T00:00:00Z",
if not title or title == '' then
-- and that's the last day of 1871, so the year is wrong.
title = '$1'
-- So fix the month 0, day 0 timestamp to become 1 January instead:
timestamp = timestamp:gsub("%-00%-00T", "-01-01T")
out[#out + 1] = parseDateFull(timestamp, dateprecision, date_format, date_addon)
end
title = mw.ustring.gsub( title, '$1', value )
 
return '[' .. link .. ' ' .. title .. ']'
end
return table.concat(out, ", ")
 
end
return value
p.getQualifierDateValue = function(frame)
local date_format = mw.text.trim(frame.args[4] or i18n["datetime"]["default-format"])
local date_addon = mw.text.trim(frame.args[5] or i18n["datetime"]["default-addon"])
local function outputHook(value)
local timestamp = value.datavalue.value.time
return parseDateValue(timestamp, date_format, date_addon)
end
return (getQualifier(frame, outputHook))
end
 
-- This is used to fetch all of the images with a particular property, e.g. image (P18), Gene Atlas Image (P692), etc.
--[[
-- Parameters are | propertyID | value / FETCH_WIKIDATA / nil | separator (default=space) | size (default=frameless)
Функция для оформления числовых значений
-- It will return a standard wiki-markup [[File:Filename | size]] for each image with a selectable size and separator (which may be html)
 
-- e.g. {{#invoke:Wikidata|getImages|P18|FETCH_WIKIDATA}}
Принимает: объект-значение и таблицу параметров,
-- e.g. {{#invoke:Wikidata|getImages|P18|FETCH_WIKIDATA|<br>|250px}}
Возвращает: строку оформленного текста
-- If a property is chosen that is not of type "commonsMedia", it will return empty text.
]]
p.getImages = function(frame)
local function formatQuantity( value, options )
local sep = mw.text.trim(frame.args[3] or " ")
-- диапазон значений
local amountimgsize = stringmw.gsubtext.trim( valueframe.args['amount'4], '^%+', ''or "frameless");
local go, errorOrentity, claims = parseInput(frame)
local lang = mw.language.getContentLanguage();
if not go then
local langCode = lang:getCode();
return errorOrentity
 
local function formatNum( number, sigfig )
sigfig = sigfig or 12 -- округление до 12 знаков после запятой, на 13-м возникает ошибка в точности
local mult = 10^sigfig;
number = math.floor( number * mult + 0.5 ) / mult;
return string.gsub( lang:formatNum( number ), '^-', '−' );
end
local entity = errorOrentity
 
if (claims[1] and claims[1].mainsnak.datatype == "commonsMedia") then
local out = formatNum( tonumber( amount ) );
local out = {}
if value.upperBound then
for k, v in pairs(claims) do
local diff = tonumber( value.upperBound ) - tonumber( amount )
local filename = v.mainsnak.datavalue.value
if diff > 0 then -- временная провека, пока у большинства значений не будет убрано ±0
out[#out + 1] = "[[File:" .. filename .. "|" .. imgsize .. "]]"
-- Пробуем понять до какого знака округлять
local integer, dot, decimals, expstr = value.upperBound:match( '^+?-?(%d*)(%.?)(%d*)(.*)' )
local prec
if dot == '' then
prec = -integer:match('0*$'):len()
else
prec = #decimals
end
bound = formatNum( diff, prec )
if string.match( bound, 'E%-(%d+)' ) then -- если в экспоненциальном формате
digits = tonumber( string.match( bound, 'E%-(%d+)' ) ) - 2
bound = formatNum( diff * 10 ^ digits, prec )
bound = string.sub( bound, 0, 2 ) .. string.rep( '0', digits ) .. string.sub( bound, -string.len( bound ) + 2 )
end
out = out .. ' ± ' .. bound
end
return table.concat(out, sep)
else
return ""
end
end
 
-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
if options.unit and options.unit ~= '' then
-- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
if options.unit ~= '-' then
-- uses the newer mw.wikibase calls instead of directly using the snaks
out = out .. ' ' .. options.unit
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
end
p.getTAValue = function(frame)
elseif value.unit and string.match( value.unit, 'http://www.wikidata.org/entity/' ) then
local ent = mw.wikibase.getEntityObject()
local unitEntityId = string.gsub( value.unit, 'http://www.wikidata.org/entity/', '' );
local props = ent:formatPropertyValues('P1323')
if unitEntityId ~= 'undefined' then
local out = {}
local wbStatus, unitEntity = pcall( mw.wikibase.getEntity, unitEntityId );
local t = {}
if wbStatus == true and unitEntity then
for k, v in pairs(props) do
if unitEntity.claims.P2370 and
unitEntity.claims.P2370[1].mainsnak.snaktypeif k == 'value' andthen
t = mw.text.split( v, ", ")
not value.upperBound and
for k2, v2 in pairs(t) do
options.siConversion == true
out[#out + 1] = "[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
then
conversionToSIunit = string.gsub( unitEntity.claims.P2370[1].mainsnak.datavalue.value.amount, '^%+', '' );
if math.floor( math.log10( conversionToSIunit )) ~= math.log10( conversionToSIunit ) then
-- Если не степени десятки (переводить сантиметры в метры не надо!)
outValue = tonumber( amount ) * conversionToSIunit
if ( outValue > 0 ) then
-- Пробуем понять до какого знака округлять
local integer, dot, decimals, expstr = amount:match( '^(%d*)(%.?)(%d*)(.*)' )
local prec
if dot == '' then
prec = -integer:match('0*$'):len()
else
prec = #decimals
end
local adjust = math.log10( math.abs( conversionToSIunit )) + math.log10( 2 )
local minprec = 1 - math.floor( math.log10( outValue ) + 2e-14 );
out = formatNum( outValue, math.max( math.floor( prec + adjust ), minprec ));
else
out = formatNum( outValue, 0 )
end
unitEntityId = string.gsub( unitEntity.claims.P2370[1].mainsnak.datavalue.value.unit, 'http://www.wikidata.org/entity/', '' );
wbStatus, unitEntity = pcall( mw.wikibase.getEntity, unitEntityId );
end
end
local writingSystemElementId = 'Q8209';
local langElementId = 'Q7737';
local label = getLabelWithLang( context, options, unitEntity.id, nil, { "P5061", "P558", "P558" }, {
'P5061[language:' .. langCode .. ']',
'P558[P282:' .. writingSystemElementId .. ', P407:' .. langElementId .. ']',
'P558[!P282][!P407]'
} );
out = out .. ' ' .. label;
end
end
end
local ret = table.concat(out, "<br> ")
 
if #ret == 0 then
return out;
ret = "Invalid TA"
end
return ret
end
 
local DATATYPE_CACHE = {}
 
--[[
This is used to return an image legend from Wikidata
Get property datatype by ID.
image is property P18
image legend is property P2096
 
Call as {{#invoke:Wikidata |getImageLegend | <PARAMETER> | lang=<ISO-639code> |id=<QID>}}
@param string Property ID, e.g. 'P123'.
Returns PARAMETER, unless it is equal to "FETCH_WIKIDATA", from Item QID (expensive call)
@return string Property datatype, e.g. 'commonsMedia', 'time' or 'url'.
If QID is omitted or blank, the current article is used (not an expensive call)
If lang is omitted, it uses the local wiki language, otherwise it uses the provided ISO-639 language code
ISO-639: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447
 
Ranks are: 'preferred' > 'normal'
This returns the label from the first image with 'preferred' rank
Or the label from the first image with 'normal' rank if preferred returns nothing
Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua
]]
 
local function getPropertyDatatype( propertyId )
p.getImageLegend = function(frame)
if not propertyId or not string.match( propertyId, '^P%d+$' ) then
-- look for named parameter id; if it's blank make it nil
return nil;
local id = frame.args.id
if id and (#id == 0) then
id = nil
end
local cached = DATATYPE_CACHE[propertyId];
if (cached ~= nil) then return cached; end
 
-- look for named parameter lang
local wbStatus, propertyEntity = pcall( mw.wikibase.getEntity, propertyId );
-- it should contain a two-character ISO-639 language code
if wbStatus ~= true or not propertyEntity then
-- if it's blank fetch the language of the local wiki
return nil;
local lang = frame.args.lang
if (not lang) or (#lang < 2) then
lang = mw.language.getContentLanguage().code
end
mw.log("Loaded datatype " .. propertyEntity.datatype .. " of " .. propertyId .. ' from wikidata, consider passing datatype argument to formatProperty call or to Wikidata/config' )
 
-- first unnamed parameter is the local parameter, if supplied
DATATYPE_CACHE[propertyId] = propertyEntity.datatype;
local input_parm = mw.text.trim(frame.args[1] or "")
return propertyEntity.datatype;
if input_parm == "FETCH_WIKIDATA" then
end
local ent = mw.wikibase.getEntityObject(id)
 
local imgs
local function formatLangRefs( options )
if ent and ent.claims then
local langRefs = ''
imgs = ent.claims.P18
if ( options.qualifiers and options.qualifiers.P407 ) then
end
for i, qualifier in pairs( options.qualifiers.P407 ) do
local imglbl
if ( qualifier
if imgs then
and qualifier.datavalue
-- look for an image with 'preferred' rank
and qualifier.datavalue.type == 'wikibase-entityid' ) then
for k1, v1 in pairs(imgs) do
local langRefEntity = getEntityFromId( qualifier.datavalue.value.id )
if (v1.rank langRefEntity== "preferred" and langRefEntityv1.claimsqualifiers )and v1.qualifiers.P2096 then
local langRefCodeClaimsimglbls = WDSv1.filter( langRefEntityqualifiers.claims, 'P218' )P2096
for k2, v2 in pairs(imglbls) do
if langRefCodeClaims then
if v2.datavalue.value.language == lang then
for _, claim in pairs( langRefCodeClaims ) do
ifimglbl (= claimv2.mainsnakdatavalue.value.text
and claim.mainsnakbreak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.type == 'string' ) then
local langRefCode = claim.mainsnak.datavalue.value
langRefs = langRefs .. '&#8203;' .. options.frame:expandTemplate{ title = 'ref-' ..langRefCode }
end
end
end
end
end
-- if we don't find one, look for an image with 'normal' rank
end
if (not imglbl) then
end
for k1, v1 in pairs(imgs) do
 
if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
return langRefs
local imglbls = v1.qualifiers.P2096
end
for k2, v2 in pairs(imglbls) do
 
if v2.datavalue.value.language == lang then
local function getDefaultValueFunction( datavalue, datatype )
imglbl = v2.datavalue.value.text
-- вызов обработчиков по умолчанию для известных типов значений
break
if datavalue.type == 'wikibase-entityid' then
end
-- Entity ID
return function( context, options, value ) return formatEntityId( context, options, getEntityIdFromValue( value ) ) end;
elseif datavalue.type == 'string' then
-- String
if datatype and datatype == 'commonsMedia' then
-- Media
return function( context, options, value )
if options.caption and options.caption ~= '' then
options.local_caption = options.caption;
elseif options.description and options.description ~= '' then
options.local_caption = options.description;
end
options.caption = ''
options.description = ''
if options.qualifiers and options.qualifiers.P2096 then
for i, qualifier in pairs( options.qualifiers.P2096 ) do
if ( qualifier
and qualifier.datavalue
and qualifier.datavalue.type == 'monolingualtext'
and qualifier.datavalue.value
and qualifier.datavalue.value.language == contentLanguageCode ) then
options.caption = qualifier.datavalue.value.text
options.description = qualifier.datavalue.value.text
break
end
end
end
if options['appendTimestamp'] and options.qualifiers and options.qualifiers.P585 and options.qualifiers.P585[1] then
local moment = formatDatavalue (context, options, options.qualifiers.P585[1].datavalue, 'time')
if not options.caption or options.caption == '' then
options.caption = moment
options.description = moment
else
options.caption = options.caption .. ', ' .. moment
options.description = options.description .. ', ' .. moment
end
end
return formatCommonsMedia( value, options )
end;
elseif datatype and datatype == 'external-id' then
-- External ID
return function( context, options, value )
return formatExternalId( value, options )
end
elseif datatype and datatype == 'math' then
-- Math formula
return function( context, options, value )
return formatMath( value, options )
end
elseif datatype and datatype == 'url' then
-- URL
return function( context, options, value )
local moduleUrl = require( 'Module:URL' )
local langRefs = formatLangRefs( options )
if not options.length or options.length == '' then
options.length = math.max( 18, 25 - #langRefs )
end
return moduleUrl.formatUrlSingle( context, options, value ) .. langRefs
end
end
return imglbl
return function( context, options, value ) return value end;
elseif datavalue.type == 'monolingualtext' then
-- моноязычный текст (строка с указанием языка)
return function( context, options, value )
if ( options.monolingualLangTemplate == 'lang' ) then
if ( value.language == contentLanguageCode ) then
return value.text;
end
return options.frame:expandTemplate{ title = 'lang-' .. value.language, args = { value.text } };
elseif ( options.monolingualLangTemplate == 'ref' ) then
return '<span class="lang" lang="' .. value.language .. '">' .. value.text .. '</span>' .. options.frame:expandTemplate{ title = 'ref-' .. value.language };
else
return '<span class="lang" lang="' .. value.language .. '">' .. value.text .. '</span>';
end
end;
elseif datavalue.type == 'globecoordinate' then
-- географические координаты
return function( context, options, value ) return formatGlobeCoordinate( value, options ) end;
elseif datavalue.type == 'quantity' then
return function( context, options, value ) return formatQuantity( value, options ) end;
elseif datavalue.type == 'time' then
return function( context, options, value )
local moduleDate = require( 'Module:Wikidata/date' )
return moduleDate.formatDate( context, options, value );
end;
else
return input_parm
-- во всех стальных случаях возвращаем ошибку
throwError( 'unknown-datavalue-type' )
end
end
 
-- This is used to get the QIDs of all of the values of a property, as a comma separated list if multiple values exist
--[[
-- Usage: {{#invoke:Wikidata |getPropertyIDs |<PropertyID> |FETCH_WIKIDATA}}
Функция для оформления значений (value)
-- Usage: {{#invoke:Wikidata |getPropertyIDs |<PropertyID> |<InputParameter> |qid=<QID>}}
Подробнее о значениях см. d:Wikidata:Glossary/ru
 
p.getPropertyIDs = function(frame)
Принимает: объект-значение и таблицу параметров,
local go, errorOrentity, propclaims = parseInput(frame)
Возвращает: строку оформленного текста
if not go then
]]
return errorOrentity
function formatDatavalue( context, options, datavalue, datatype )
if ( not context ) then error( 'context not specified' ); end;
if ( not options ) then error( 'options not specified' ); end;
if ( not datavalue ) then error( 'datavalue not specified' ); end;
if ( not datavalue.value ) then error( 'datavalue.value is missng' ); end;
 
-- проверка на указание специализированных обработчиков в параметрах,
-- переданных при вызове
context.formatValueDefault = getDefaultValueFunction( datavalue, datatype );
local functionToCall = getUserFunction( options, 'value', context.formatValueDefault );
return functionToCall( context, options, datavalue.value );
end
 
local DEFAULT_BOUNDARIES = { os.time() * 1000, os.time() * 1000};
 
--[[
Функция для оформления идентификатора сущности
 
Принимает: строку индентификатора (типа Q42) и таблицу параметров,
Возвращает: строку оформленного текста
]]
function formatEntityId( context, options, entityId )
-- получение локализованного названия
local boundaries = nil
if options.qualifiers then
boundaries = p.getTimeBoundariesFromQualifiers( frame, context, { qualifiers = options.qualifiers } )
end
local entity = errorOrentity
if not boundaries then
-- if wiki-linked value collect the QID in a table
boundaries = DEFAULT_BOUNDARIES;
if (propclaims[1] and propclaims[1].mainsnak.snaktype == "value" and propclaims[1].mainsnak.datavalue.type == "wikibase-entityid") then
end
local out = {}
local label, labelLanguageCode = getLabelWithLang( context, options, entityId, boundaries )
for k, v in pairs(propclaims) do
 
out[#out + 1] = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
-- определение соответствующей показываемому элементу категории
local category = p.extractCategory( context, options, { id = entityId } )
 
-- получение ссылки по идентификатору
local link = mw.wikibase.sitelink( entityId )
if link then
-- ссылка на категорию, а не добавление страницы в неё
if mw.ustring.match( link, '^' .. mw.site.namespaces[ 14 ].name .. ':' ) then
link = ':' .. link
end
if label and not options.rawArticle then
local a = link == label and ('[[' .. link .. ']]') or '[[' .. link .. '|' .. label .. ']]';
if ( contentLanguageCode ~= labelLanguageCode ) then
return a .. getCategoryByCode( 'links-to-entities-with-missing-local-language-label' ) .. category;
else
return a .. category;
end
else
return '[[' .. link .. ']]' .. category;
end
return table.concat(out, ", ")
else
-- not a wikibase-entityid, so return empty
return ""
end
 
if label then
-- красная ссылка
-- TODO: разобраться, почему не всегда есть options.frame
local title = mw.title.new( label );
if title and not title.exists and options.frame then
local redLink = options.frame:expandTemplate{ title='Калып:Красная ссылка с рыбой', args = { entityId, label } };
return redLink .. '<sup>[[:d:' .. entityId .. '|[d]]]</sup>' .. category;
end
 
-- TODO: перенести до проверки на существование статьи
local sup = '';
if ( not options.format or options.format ~= 'text' )
and entityId ~= 'Q6581072' and entityId ~= 'Q6581097' -- TODO: переписать на format=text
then
sup = '<sup class="plainlinks noprint">[//www.wikidata.org/wiki/' .. entityId .. '?uselang=' .. contentLanguageCode .. ' [d&#x5d;]</sup>'
end
 
-- одноимённая статья уже существует - выводится текст и ссылка на ВД
return '<span class="iw" data-title="' .. label .. '">' .. label
.. sup
.. '</span>' .. category
end
-- сообщение об отсутвии локализованного названия
-- not good, but better than nothing
return '[[:d:' .. entityId .. '|' .. entityId .. ']]<span style="border-bottom: 1px dotted; cursor: help; white-space: nowrap" title="В Викиданных нет русской подписи к элементу. Вы можете помочь, указав русский вариант подписи.">?</span>' .. getCategoryByCode( 'links-to-entities-with-missing-label' ) .. category;
end
 
-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata
--[[
function p.pageId(frame)
Функция для формирования категории на основе wikidata/config
local entity = mw.wikibase.getEntityObject()
]]
if not entity then return nil else return entity.id end
function p.extractCategory( context, options, value )
if ( not options.category or options.nocat ) then
return '';
end
local propertyId = string.gsub( options.category, '([^Pp0-9].*)$', '');
local wbStatus, claims = pcall( mw.wikibase.getAllStatements, value.id, propertyId );
if ( wbStatus ~= true or not claims ) then return ''; end
allClaims = {}
allClaims[ propertyId ] = claims
claims = WDS.filter( allClaims, options.category )
if not claims then return ''; end
for _, claim in pairs( claims ) do
if ( claim
and claim.mainsnak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.type == 'wikibase-entityid' ) then
local catEntityId = claim.mainsnak.datavalue.value.id;
local wbStatus, catSiteLink = pcall( mw.wikibase.getSitelink, catEntityId );
 
if ( wbStatus == true and catSiteLink ) then
return '[[' .. catSiteLink .. ']]';
end
end
end
 
return '';
end
--[[
Функция для оформления утверждений (statement)
Подробнее о утверждениях см. d:Wikidata:Glossary/ru
 
function p.claim(frame)
Принимает: таблицу параметров
local property = frame.args[1] or ""
Возвращает: строку оформленного текста, предназначенного для отображения в статье
local id = frame.args["id"]
]]
local qualifierId = frame.args["qualifier"]
-- устаревшее имя, не использовать
local parameter = frame.args["parameter"]
function p.formatStatements( frame )
local list = frame.args["list"]
return p.formatProperty( frame );
local references = frame.args["references"]
end
local showerrors = frame.args["showerrors"]
local default = frame.args["default"]
if default then showerrors = nil end
 
-- get wikidata entity
--[[
local entity = mw.wikibase.getEntityObject(id)
Получение параметров, которые обычно используются для вывода свойства.
if not entity then
]]
if showerrors then return printError("entity-not-found") else return default end
function getPropertyParams( propertyId, datatype, params )
local config = getConfig();
 
-- Различные уровни настройки параметров, по убыванию приоритета
local propertyParams = {};
 
-- 1. Параметры, указанные явно при вызове
if params then
for key, value in pairs( params ) do
if value ~= '' then
propertyParams[ key ] = value;
end
end
end
-- fetch the first claim of satisfying the given property
 
local claims = findClaims(entity, property)
-- 2. Настройки конкретного параметра
if config[not 'properties'claims ]or andnot configclaims[ 'properties' ][ propertyId 1] then
if showerrors then return printError("property-not-found") else return default end
for key, value in pairs( config[ 'properties' ][ propertyId ] ) do
if propertyParams[ key ] == nil then
propertyParams[ key ] = value;
end
end
end
 
-- get initial sort indices
-- 3. Указанный пресет настроек
local sortindices = {}
if propertyParams[ 'preset' ] and config[ 'presets' ] and
for idx in pairs(claims) do
config[ 'presets' ][ propertyParams[ 'preset' ] ]
sortindices[#sortindices + 1] = idx
then
for key, value in pairs( config[ 'presets' ][ propertyParams[ 'preset' ] ] ) do
if propertyParams[ key ] == nil then
propertyParams[ key ] = value;
end
end
end
-- sort by claim rank
 
local comparator = function(a, b)
local datatype = datatype or params.datatype or propertyParams.datatype or getPropertyDatatype( propertyId );
local rankmap = { deprecated = 2, normal = 1, preferred = 0 }
if propertyParams.datatype == nil then
local ranka = rankmap[claims[a].rank or "normal"] .. string.format("%08d", a)
propertyParams.datatype = datatype;
local rankb = rankmap[claims[b].rank or "normal"] .. string.format("%08d", b)
return ranka < rankb
end
table.sort(sortindices, comparator)
 
local result
-- 4. Настройки для типа данных
local error
if datatype and config[ 'datatypes' ] and config[ 'datatypes' ][ datatype ] then
if list then
for key, value in pairs( config[ 'datatypes' ][ datatype ] ) do
local value
if propertyParams[ key ] == nil then
-- iterate over all elements and return their value (if existing)
propertyParams[ key ] = value;
result = {}
end
for idx in pairs(claims) do
local claim = claims[sortindices[idx]]
value, error = getValueOfClaim(claim, qualifierId, parameter)
if not value and showerrors then value = error end
if value and references then value = value .. getReferences(frame, claim) end
result[#result + 1] = value
end
result = table.concat(result, list)
else
-- return first element
local claim = claims[sortindices[1]]
result, error = getValueOfClaim(claim, qualifierId, parameter)
if result and references then result = result .. getReferences(frame, claim) end
end
 
if result then return result else
-- 5. Общие настройки для всех свойств
if showerrors then return error else return default end
if config[ 'global' ] then
for key, value in pairs( config[ 'global' ] ) do
if propertyParams[ key ] == nil then
propertyParams[ key ] = value;
end
end
end
 
return propertyParams;
end
 
-- look into entity object
function p.formatProperty( frame )
function p.ViewSomething(frame)
local args = frame.args
local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
 
local id = f.args.id
-- проверка на отсутствие обязательного параметра property
if notid args.propertyand (#id == 0) then
id = nil
throwError( 'property-param-not-provided' )
end
local data = mw.wikibase.getEntityObject(id)
local override;
if not data then
local propertyId = mw.language.getContentLanguage():ucfirst( string.gsub( args.property, '([^Pp0-9].*)$', function(w)
return nil
if string.sub( w, 1, 1 ) == '~' then override = w; end
return '';
end ) )
args = getPropertyParams( propertyId, nil, args );
if (override) then
args[override:match('[,~]([^=]*)=')] = override:match('=(.*)')
args['property'] = propertyId
end
 
local datatypei = args.datatype;1
while true do
 
local index = f.args[i]
-- проброс всех параметров из шаблона {wikidata} и параметра from откуда угодно
if not index then
p_frame = frame
if type(data) == "table" then
while p_frame do
return mw.text.jsonEncode(data, mw.text.JSON_PRESERVE_KEYS + mw.text.JSON_PRETTY)
if p_frame:getTitle() == mw.site.namespaces[10].name .. ':Wikidata' then
copyTo( p_frame.args, args, true );
end
if p_frame.args and p_frame.args.from and p_frame.args.from ~= '' then
args.entityId = p_frame.args.from;
end
p_frame = p_frame:getParent();
end
 
args.plain = toBoolean( args.plain, false );
args.nocat = toBoolean( args.nocat, false );
args.references = toBoolean( args.references, true );
 
-- если значение передано в параметрах вызова то выводим только его
if args.value and args.value ~= '' then
-- специальное значение для скрытия Викиданных
if args.value == '-' then
return ''
end
local value = args.value
 
-- опция, запрещающая оформление значения, поэтому никак не трогаем
if args.plain then
return value
end
 
-- обработчики по типу значения
local wrapperExtraArgs = ''
if args['value-module'] and args['value-function'] and not string.find( value, '[%[%]%{%}]' ) then
local func = getUserFunction( args, 'value' );
value = func( {}, args, value );
elseif datatype == 'commonsMedia' then
value = formatCommonsMedia( value, args );
elseif datatype == 'external-id' and not string.find( value, '[%[%]%{%}]' ) then
wrapperExtraArgs = wrapperExtraArgs .. ' data-wikidata-external-id="' .. mw.text.encode( value ).. '"';
value = formatExternalId( value, args );
elseif datatype == 'math' then
value = formatMath( value, args );
elseif datatype == 'url' then
local moduleUrl = require( 'Module:URL' );
if not args.length or args.length == '' then
args.length = 25
end
value = moduleUrl.formatUrlSingle( nil, args, value );
end
 
-- оборачиваем в тег для JS-функций
if string.match( propertyId, '^P%d+$' ) then
value = mw.text.trim( value )
 
-- временная штрафная категория для исправления табличных вставок
if ( propertyId ~= 'P166'
and string.match( value, '<t[dr][ >]' )
and not string.match( value, '<table >]' )
and not string.match( value, '^%{%|' ) ) then
value = value .. getCategoryByCode( 'value-contains-table' )
else
return tostring(data)
value = wrapFormatProperty( value, 'class="no-wikidata"'
.. wrapperExtraArgs .. ' data-wikidata-property-id="'
.. propertyId .. '"' );
end
end
 
data = data[index] or data[tonumber(index)]
-- добавляем категорию-маркер
if not args.nocatdata then
return
local pageTitle = mw.title.getCurrentTitle();
if pageTitle.namespace == 0 then
value = value .. getCategoryByCode( 'local-value-present' );
end
end
 
i = i + 1
return value
end
end
 
-- getting sitelink of a given wiki
if ( args.plain ) then -- вызова стандартного обработчика без оформления, если передана опция plain
-- get sitelink of current item if qid not supplied
local callArgs = { propertyId };
function p.getSiteLink(frame)
if args.entityId then
callArgs.from local qid = frame.args.entityId;qid
if qid == "" then qid = nil end
end
local f = mw.text.trim( frame.args[1] or "")
return frame:callParserFunction( '#property', callArgs );
local entity = mw.wikibase.getEntity(qid)
if not entity then
return
end
local link = entity:getSitelink( f )
if not link then
return
end
return link
 
g_frame = frame
-- после проверки всех аргументов -- вызов функции оформления для свойства (набора утверждений)
return formatProperty( args )
end
 
function p.Dump(frame)
--[[
local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
Функция оформления ссылок на источники (reference)
local data = mw.wikibase.getEntityObject(f.args.id)
Подробнее о ссылках на источники см. d:Wikidata:Glossary/ru
if not data then
 
return i18n.warnDump
Экспортируется в качестве зарезервированной точки для вызова из функций-расширения вида claim-module/claim-function через context
Вызов из других модулей напрямую осуществляться не должен (используйте frame:expandTemplate вместе с одним из специлизированных шаблонов вывода значения свойства).
 
Принимает: объект-таблицу утверждение
Возвращает: строку оформленных ссылок для отображения в статье
]]
function formatRefs( context, options, statement )
if ( not context ) then error( 'context not specified' ); end;
if ( not options ) then error( 'options not specified' ); end;
if ( not options.entity ) then error( 'options.entity missing' ); end;
if ( not statement ) then error( 'statement not specified' ); end;
 
if ( not outputReferences ) then
return '';
end
 
local referencesi = {};1
while true do
if ( statement.references ) then
local index = f.args[i]
if not index then
return "<pre>"..mw.dumpObject(data).."</pre>".. i18n.warnDump
end
 
data = data[index] or data[tonumber(index)]
local allReferences = statement.references;
if not data then
local hasNotDeprecated = false;
return i18n.warnDump
local displayCount = 0;
for _, reference in pairs( statement.references ) do
if ( reference.snaks
and reference.snaks.P248
and reference.snaks.P248[1]
and reference.snaks.P248[1].datavalue
and reference.snaks.P248[1].datavalue.value.id ) then
local entityId = reference.snaks.P248[1].datavalue.value.id;
if ( not deprecatedSources[entityId] ) then
hasNotDeprecated = true;
end
end
end
 
i = i + 1
for _, reference in pairs( statement.references ) do
local display = true;
if ( hasNotDeprecated ) then
if ( reference.snaks
and reference.snaks.P248
and reference.snaks.P248[1]
and reference.snaks.P248[1].datavalue
and reference.snaks.P248[1].datavalue.value.id ) then
local entityId = reference.snaks.P248[1].datavalue.value.id;
if ( deprecatedSources[entityId] ) then
display = false;
end
end
end
if ( displayCount > 2 ) then
if ( options.entity and options.property ) then
local moreReferences = '<sup>[[d:' .. options.entity.id .. '#' .. string.upper( options.property ) .. '|[…]]]</sup>';
table.insert( references, moreReferences );
end
break;
end
if ( display == true ) then
local refText = moduleSources.renderReference( g_frame, options.entity, reference );
if ( refText ~= '' ) then
table.insert( references, refText );
displayCount = displayCount + 1;
end
end
end
end
return table.concat( references );
end