Модуль:Wikidata/chronology: различия между версиями

Материал из Энциклопедия автомобильных номеров мира
Перейти к навигации Перейти к поиску
/>Oleg Yunakov
м (Защитил страницу Модуль:Wikidata/chronology: критический шаблон или модуль: https://ru.wikipedia.org/w/index.php?title=ЭАНМ:Установка_защиты&oldid=117401039#Шаблоны ([Редактирование=администраторы и инженеры] (бессрочно) [Переименование=администраторы и инженеры] (бессрочно)))
Строка 1: Строка 1:
#перенаправление [[Шаблон:ПозКарта Соединённые Штаты Америки Индиана]]
local p = {} -- p stands for package
 
-- technical functions for takeAdjacentNumbersFromStrings
function isYear(number) -- TODO: settings not hardcoded
return number >= 1800 and number <= 2100
end
 
function isAr(number)
return number >= 0 and number < 100
end
 
function notTooFar(number1, number2, maximalPeriod)
return number2 - number1 > 0 and number2 - number1 <= maximalPeriod
end
 
-- takes two strings and returns either two substrings that form the only difference between them or nil
-- considers several possible formats of substrings given in options.formats
function takeAdjacentNumbersFromStrings(options, string1, string2)
if type(string1) == 'string' and type(string2) == 'string' then
local formats = options.formats or '' -- TODO: not repeat with properties
if formats == '' then
formats = 'year, year/ar, year/year'
elseif formats == '-' then
formats = ''
end
local formats = mw.text.split(formats, ', ?')
local line = '!' .. string1 .. '!!' .. string2.. '!' -- -- TODO: without hacks
local maximalPeriod = tonumber(options.maximalPeriod) or 5 -- TODO: here or in main function?
for _, format in pairs(formats) do
if format == 'year' or format == 'number' then
local match = {mw.ustring.match(line, '^(.*%D)(%d+)(%D.*)%1(%d+)%3$')}
if #match > 0 then
local number1 = tonumber(match[2])
local number2 = tonumber(match[4])
if notTooFar(number1, number2, maximalPeriod) then
if (format == 'year' and isYear(number1) and isYear(number2))
or (format == 'number')
then
return {number1, number2}
end
end
end
elseif format == 'year/ar' or format == 'year/year' then
local match = {mw.ustring.match(line, '^(.*%D)((%d+)[-–\/](%d+))(%D.*)%1((%d+)\/(%d+))%5$')}
if #match > 0 then
local period1 = match[2]
local period1_start = tonumber(match[3])
local period1_end = tonumber(match[4])
local period2 = match[6]
local period2_start = tonumber(match[7])
local period2_end = tonumber(match[8])
if notTooFar(period1_start, period2_start, maximalPeriod) and isYear(period1_start) and isYear(period2_start)
and period2_start - period1_start == period2_end - period1_end
then
if (format == 'year/ar' and isAr(period1_end) and isAr(period2_end))
or (format == 'year/year' and isYear(period1_end) and isYear(period2_end))
then
return {period1, period2}
end
end
end
end
end
end
return nil
end
 
-- takes two Wikidata entities and returns either two strings or nil
-- considers sitelinks and labels in the local langauge and in English
function takeAdjacentNumbersFromEntities(options, entity1, entity2)
if entity1 and entity2 then
local adjacentNumbers = nil
local languageCodes = {mw.getContentLanguage():getCode(), 'en'}
for _, languageCode in pairs(languageCodes) do
local wikiCode = languageCode .. 'wiki'
local sitelink1 = entity1:getSitelink(wikiCode)
local sitelink2 = entity2:getSitelink(wikiCode)
adjacentNumbers = takeAdjacentNumbersFromStrings(options, sitelink1, sitelink2)
if adjacentNumbers then
return adjacentNumbers
end
local label1 = entity1:getLabel(languageCode) -- TODO: get rid of fallback?
local label2 = entity2:getLabel(languageCode)
adjacentNumbers = takeAdjacentNumbersFromStrings(options, label1, label2)
if adjacentNumbers then
return adjacentNumbers
end
end
end
return nil
end
 
function formatAdjacentSnak(context, options, snak)
local direction = options.direction or ''
if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.id then
local mainText = nil
local adjacentEntity = mw.wikibase.getEntity(snak.datavalue.value.id)
if direction == 'P155' then -- previous
local adjacentNumbers = takeAdjacentNumbersFromEntities(options, adjacentEntity, options.entity) -- or reverse order
if adjacentNumbers then
mainText = adjacentNumbers[1] -- or 2
end
elseif direction == 'P156' then -- next
local adjacentNumbers = takeAdjacentNumbersFromEntities(options, options.entity, adjacentEntity)
if adjacentNumbers then
mainText = adjacentNumbers[2]
end
end
-- options should not be changed, as they are reused for P155 and P156
local optionsCopy = {}
for k, v in pairs(options) do
optionsCopy[k] = v
end
if (not optionsCopy.text) and mainText then
local prefix = options.prefix or ''
local postfix = options.postfix or ''
optionsCopy.text = prefix .. mainText .. postfix
end
local link = context.formatSnak(optionsCopy, snak)
if mainText or (options.formats and options.formats == '-') then
return link
else
return link .. '[[Категория:ЭАНМ:Статьи с несокращаемой хронологией]]'
end
end
return nil
end
 
-- function is available from outside, see documentation
function p.formatAdjacentProperty(context, options)
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 options.value == '-' then
return ''
end
 
if options.value then
return options.value
end
 
local properties = options.property or '' -- TODO: properties vs. property?
if properties == '' then
properties = 'Q'
elseif properties == '-' then
properties = ''
end
local properties = mw.text.split(properties, ', ?')
local direction = options.direction or '' -- TODO: not repeating inside
local formattedClaims = {}
 
for _, property in pairs(properties) do
if property == 'Q' then
local claims = context.selectClaims(options, direction)
if claims then
for _, claim in pairs(claims) do
if claim.mainsnak then
local link = formatAdjacentSnak(context, options, claim.mainsnak)
if link and link ~= '' then
local formattedClaim = '<span class="wikidata-claim" data-wikidata-property-id="' .. direction .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. link .. '</span>'
table.insert(formattedClaims, formattedClaim)
end
end
end
end
elseif mw.ustring.match(property, '^P%d+$') then
local claims = context.selectClaims(options, property)
if claims then
for _, claim in pairs(claims) do
if claim.qualifiers and claim.qualifiers[direction] then
for _, snak in pairs(claim.qualifiers[direction]) do
local link = formatAdjacentSnak(context, options, snak)
if link and link ~= '' then
local formattedClaim = '<span class="wikidata-claim" data-wikidata-property-id="' .. property .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. link .. '</span>'
table.insert(formattedClaims, formattedClaim)
end
end
end
end
end
end
end
-- from wikidata.selectClaims
if options.limit and options.limit ~= '' and options.limit ~= '-'  then
local limit = tonumber(options.limit, 10);
while #formattedClaims > limit do
table.remove(formattedClaims);
end
end
-- from wikidata.formatPropertyDefault
local out = mw.text.listToText(formattedClaims, options.separator, options.conjunction)
if out ~= '' then
if options.before then
out = options.before .. out
end
if options.after then
out = out .. options.after
end
end
 
return out
end
 
return p

Версия от 21:22, 24 октября 2021

Для документации этого модуля может быть создана страница Модуль:Wikidata/chronology/doc

local p = {} -- p stands for package

-- technical functions for takeAdjacentNumbersFromStrings
function isYear(number) -- TODO: settings not hardcoded
	return number >= 1800 and number <= 2100
end

function isAr(number)
	return number >= 0 and number < 100
end

function notTooFar(number1, number2, maximalPeriod)
	return number2 - number1 > 0 and number2 - number1 <= maximalPeriod
end

-- takes two strings and returns either two substrings that form the only difference between them or nil
-- considers several possible formats of substrings given in options.formats
function takeAdjacentNumbersFromStrings(options, string1, string2)
	if type(string1) == 'string' and type(string2) == 'string' then
		local formats = options.formats or '' -- TODO: not repeat with properties
		if formats == '' then
			formats = 'year, year/ar, year/year'
		elseif formats == '-' then
			formats = ''
		end
		local formats = mw.text.split(formats, ', ?')
		
		local line = '!' .. string1 .. '!!' .. string2.. '!' -- -- TODO: without hacks
		local maximalPeriod = tonumber(options.maximalPeriod) or 5 -- TODO: here or in main function?
		
		for _, format in pairs(formats) do
			if format == 'year' or format == 'number' then
				local match = {mw.ustring.match(line, '^(.*%D)(%d+)(%D.*)%1(%d+)%3$')}
				if #match > 0 then
					local number1 = tonumber(match[2])
					local number2 = tonumber(match[4])
					
					if notTooFar(number1, number2, maximalPeriod) then
						if (format == 'year' and isYear(number1) and isYear(number2))
							or (format == 'number')
						then
							return {number1, number2}
						end
					end
				end
			elseif format == 'year/ar' or format == 'year/year' then
				local match = {mw.ustring.match(line, '^(.*%D)((%d+)[-–\/](%d+))(%D.*)%1((%d+)\/(%d+))%5$')}
				if #match > 0 then
					local period1 = match[2]
					local period1_start = tonumber(match[3])
					local period1_end = tonumber(match[4])
					local period2 = match[6]
					local period2_start = tonumber(match[7])
					local period2_end = tonumber(match[8])
					
					if notTooFar(period1_start, period2_start, maximalPeriod) and isYear(period1_start) and isYear(period2_start)
						and period2_start - period1_start == period2_end - period1_end
					then
						if (format == 'year/ar' and isAr(period1_end) and isAr(period2_end))
							or (format == 'year/year' and isYear(period1_end) and isYear(period2_end))
						then
							return {period1, period2}
						end
					end
				end
			end
		end
	end
	
	return nil
end

-- takes two Wikidata entities and returns either two strings or nil
-- considers sitelinks and labels in the local langauge and in English
function takeAdjacentNumbersFromEntities(options, entity1, entity2)
	if entity1 and entity2 then
		local adjacentNumbers = nil
		
		local languageCodes = {mw.getContentLanguage():getCode(), 'en'}
		for _, languageCode in pairs(languageCodes) do
			local wikiCode = languageCode .. 'wiki'
			local sitelink1 = entity1:getSitelink(wikiCode)
			local sitelink2 = entity2:getSitelink(wikiCode)
			adjacentNumbers = takeAdjacentNumbersFromStrings(options, sitelink1, sitelink2)
			if adjacentNumbers then
				return adjacentNumbers
			end
		
			local label1 = entity1:getLabel(languageCode) -- TODO: get rid of fallback?
			local label2 = entity2:getLabel(languageCode)
			adjacentNumbers = takeAdjacentNumbersFromStrings(options, label1, label2)
			if adjacentNumbers then
				return adjacentNumbers
			end
		end
	end
	
	return nil
end

function formatAdjacentSnak(context, options, snak)
	local direction = options.direction or ''
	
	if snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.id then
		local mainText = nil
		
		local adjacentEntity = mw.wikibase.getEntity(snak.datavalue.value.id)
		if direction == 'P155' then -- previous
			local adjacentNumbers = takeAdjacentNumbersFromEntities(options, adjacentEntity, options.entity) -- or reverse order
			if adjacentNumbers then
				mainText = adjacentNumbers[1] -- or 2
			end
		elseif direction == 'P156' then -- next
			local adjacentNumbers = takeAdjacentNumbersFromEntities(options, options.entity, adjacentEntity)
			if adjacentNumbers then
				mainText = adjacentNumbers[2]
			end
		end
		
		-- options should not be changed, as they are reused for P155 and P156
		local optionsCopy = {}
		for k, v in pairs(options) do
			optionsCopy[k] = v
		end
		if (not optionsCopy.text) and mainText then
			local prefix = options.prefix or ''
			local postfix = options.postfix or ''
			optionsCopy.text = prefix .. mainText .. postfix
		end
		
		local link = context.formatSnak(optionsCopy, snak)
		if mainText or (options.formats and options.formats == '-') then
			return link
		else
			return link .. '[[Категория:ЭАНМ:Статьи с несокращаемой хронологией]]'
		end
	end
	
	return nil
end

-- function is available from outside, see documentation
function p.formatAdjacentProperty(context, options)
	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 options.value == '-' then
		return ''
	end

	if options.value then
		return options.value
	end

	local properties = options.property or '' -- TODO: properties vs. property?
	if properties == '' then
		properties = 'Q'
	elseif properties == '-' then
		properties = ''
	end
	local properties = mw.text.split(properties, ', ?')
	
	local direction = options.direction or '' -- TODO: not repeating inside
	
	local formattedClaims = {}

	for _, property in pairs(properties) do
		if property == 'Q' then
			local claims = context.selectClaims(options, direction)
			if claims then
				for _, claim in pairs(claims) do
					if claim.mainsnak then
						local link = formatAdjacentSnak(context, options, claim.mainsnak)
						if link and link ~= '' then
							local formattedClaim = '<span class="wikidata-claim" data-wikidata-property-id="' .. direction .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. link .. '</span>'
							table.insert(formattedClaims, formattedClaim)
						end
					end
				end
			end
		elseif mw.ustring.match(property, '^P%d+$') then
			local claims = context.selectClaims(options, property)
			if claims then
				for _, claim in pairs(claims) do
					if claim.qualifiers and claim.qualifiers[direction] then
						for _, snak in pairs(claim.qualifiers[direction]) do
							local link = formatAdjacentSnak(context, options, snak)
							if link and link ~= '' then
								local formattedClaim = '<span class="wikidata-claim" data-wikidata-property-id="' .. property .. '" data-wikidata-claim-id="' .. claim.id .. '">' .. link .. '</span>'
								table.insert(formattedClaims, formattedClaim)
							end
						end
					end
				end
			end
		end
	end
	
	-- from wikidata.selectClaims
	if options.limit and options.limit ~= '' and options.limit ~= '-'  then
		local limit = tonumber(options.limit, 10);
		while #formattedClaims > limit do
			table.remove(formattedClaims);
		end
	end
	
	-- from wikidata.formatPropertyDefault
	local out = mw.text.listToText(formattedClaims, options.separator, options.conjunction)
	if out ~= '' then
		if options.before then
			out = options.before .. out
		end
		if options.after then
			out = out .. options.after
		end
	end

	return out
end

return p