You can edit almost every page by Creating an account. Otherwise, see the FAQ.

Module:Wikidata-n

Uit EverybodyWiki Bios & Wiki
Ga naar:navigatie, zoeken

local p = {}

local formatEntityId, formatSnak;

local WDS = require( 'Module:WikidataSelectors' );

local function min( prev, next )
	if ( prev == nil ) then return next;
	elseif ( prev > next ) then return next;
	else return prev; end
end

local function max( prev, next )
	if ( prev == nil ) then return next;
	elseif ( prev < next ) then return next;
	else return prev; end
end

local function getTimeBoundariesFromProperty( context, propertyId )
	mw.log( 'Get time boundaries for ' .. propertyId .. '...');

	local dateClaims = WDS.filter( context.entity.claims, propertyId );
	if ( not dateClaims or #dateClaims == 0 ) then return nil; end
	mw.log( 'Get time boundaries for ' .. propertyId .. '... Got ' .. #dateClaims .. ' date claim(s)');

	-- only support exact date so far, but need improvment
	local left = nil;
	local right = nil;

	if ( not left or not right ) then return nil; end

	mw.log( 'Time boundaries for ' .. propertyId .. ' are ' .. left .. ' and ' .. right );
	return { left, right };
end

local function getTimeBoundariesFromProperties( context, propertyIds )
	for _, propertyId in ipairs( propertyIds ) do
		local result = getTimeBoundariesFromProperty( context, propertyId );
		if result then
			return result;
		end
	end

	return nil;
end

local function getTimeBoundariesFromQualifiers( context, statement, qualifierId )
	-- only support exact date so far, but need improvment
	local left = nil;
	local right = nil;
	if ( statement.qualifiers and statement.qualifiers[qualifierId] ) then
		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

	if ( not left or not right ) then
		return nil;
	end

	return { left, right };
end

local function getParentsInBoundariesSnakImpl( context, entity, boundaries, propertyIds )
	local results = {};

	if entity.claims then
		for _, propertyId in ipairs( propertyIds ) do
			local filteredClaims = WDS.filter( entity.claims, propertyId .. '[rank:preferred, rank:normal]' );
			if filteredClaims then
				for _, claim in pairs( filteredClaims ) do
					local startBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P580' );
					local endBoundaries = getTimeBoundariesFromQualifiers( context, claim, 'P582' );
		
					if ( (startBoundaries == nil or ( startBoundaries[2] <= boundaries[1]))
							and (endBoundaries == nil or ( endBoundaries[1] >= boundaries[2]))) then
						table.insert( results, claim.mainsnak );
					end 
				end
			end

			if #results > 0 then
				break;
			end
		end
	end

	return results;
end

local function getParentsInBoundariesSnak( context, entity, boundaries )
	if ( not entity ) then error('entity must be specified'); end
	if ( type(entity) ~= 'table' ) then error('entity must be table'); end
	if ( not boundaries ) then error('boundaries must be specified'); end
	if ( type(boundaries) ~= 'table' ) then error('boundaries must be table'); end

	local results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {'P131'} )
	if not results or #results == 0 then
		results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {'P17'} )
	end
	for r, result in pairs( results ) do
		local resultId = 'Q' .. result.datavalue.value['numeric-id'];
		if ( resultId == entity.id ) then
			return nil;
		end
	end
	return results;
end

local unions = { 
	Q1140229 = true, -- political union
	Q3623811 = true, -- Экономический союз
	Q4120211 = true -- региональная организация
}

local countries = { 
	Q6256 = true, -- страна
	Q7275 = true, -- государство
	Q3624078 = true -- суверенное государство
}

local function isSkipTopLevel( entity )
	local isCountry = false;
	local isUnion = false;
	if ( entity
			and entity.claims
			and entity.claims.P31 ) then
		for c, claim in pairs( entity.claims.P31 ) do
			if ( claim
					and claim.mainsnak
					and claim.mainsnak.datavalue
					and claim.mainsnak.datavalue.value
					and claim.mainsnak.datavalue.value['numeric-id'] ) then
				local typeId = 'Q' .. claim.mainsnak.datavalue.value['numeric-id'];
				isCountry = isCountry or countries[typeId];
				isUnion = isUnion or unions[typeId];
			end
		end
	end
	return isUnion and not isCountry;
end

local function isPartOfNext(prevLabel, nextLabel)
	return (mw.ustring.len(prevLabel) > mw.ustring.len(nextLabel))
		and (mw.ustring.sub( prevLabel, mw.ustring.len(prevLabel) - mw.ustring.len(nextLabel) + 1 ) == nextLabel);
end

-- append entity id from snak to result
function insertFromSnak( snak, result )
	if ( snak 
			and snak.datavalue
			and snak.datavalue.type == 'wikibase-entityid'
			and snak.datavalue.value
			and snak.datavalue.value['entity-type'] == 'item' ) then
		table.insert( result, 'Q' .. snak.datavalue.value['numeric-id'] );
	end
end

-- get current of historic name of place
function getLabel( context, entity, boundaries )
	if not entity then
		return nil;
	end

	local lang = mw.language.getContentLanguage();
	local langCode = lang:getCode();

	-- name from label
	-- TODO: lang:getFallbackLanguages()
	local label = nil;
	if entity.labels then
		if entity.labels[langCode] and entity.labels[langCode].value then
			label = entity.labels[langCode].value;
		elseif entity.labels.en and entity.labels.en.value then
			label = entity.labels.en.value;
		end
	end

	-- name from properties
	local results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {
		'P1813[language:' .. langCode .. ']',
		'P1448[language:' .. langCode .. ']',
		'P1705[language:' .. langCode .. ']'
	} );

	for r, result in pairs( results ) do
		if result.datavalue
				and result.datavalue.value
				and result.datavalue.value.text then
			label = result.datavalue.value.text;
			break;
		end
	end

	return label;
end

local function calculateEndDateTimestamp( 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 ( statement.qualifiers and statement.qualifiers.P582 ) then
		for i, qualifier in ipairs(statement.qualifiers.P582 ) do
			local parsedTime = context.parseTimeFromSnak( qualifier );
			if ( parsedTime ) then
				return parsedTime;
			end
		end
	end

	-- TODO: check other "end" properties

	-- no death day
	return os.time() * 1000;
end

function getFlag( context, countryEntityId, actualDate )

	local countryEntity = mw.wikibase.getEntity( countryEntityId );
	if ( not countryEntity or not countryEntity.claims or not countryEntity.claims.P41 ) then
		return nil;
	end

	local countryFlags = {};
	local flagImageStatements = countryEntity.claims.P41;
	for _, flagImageStatement in pairs( countryEntity.claims.P41 ) do
		if ( flagImageStatement.rank ~= 'deprecated' ) then
			local flagImage;
			if ( flagImageStatement and flagImageStatement.mainsnak and flagImageStatement.mainsnak.datavalue and flagImageStatement.mainsnak.datavalue.value ) then
				flagImage = flagImageStatement.mainsnak.datavalue.value;
			end
			local flagStartTime = -9223372036854775808;
			if ( flagImage ) then
				countryFlags[ flagStartTime ] = flagImage;
			end
		end
	end

	local goodFlag = nil;
	if ( countryFlags ) then
		local ordered_dates = {}
		for flagBeginDate in pairs(countryFlags) do
			table.insert(ordered_dates, flagBeginDate)
		end
		table.sort(ordered_dates)

		for i = 1, #ordered_dates do
			local flagBeginDate, flag = ordered_dates[i], countryFlags[ ordered_dates[i] ];
			if ( actualDate >= flagBeginDate ) then
				goodFlag = flag;
			end
		end
	end
	if ( goodFlag ) then
		return '[[File:' .. goodFlag .. '|20x15px|border]]';
	end
	return nil;
end

function formatCountryClaimWithFlag( 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 is missing') end;
	if (not statement) then error('statement not specified') end;

	local countryEntityId = nil;
	local countryEntity = nil;
	if ( statement.mainsnak and statement.mainsnak.datavalue and statement.mainsnak.datavalue.value and statement.mainsnak.datavalue.value["numeric-id"] ) then
		countryEntityId = 'Q' .. statement.mainsnak.datavalue.value["numeric-id"];
		countryEntity = mw.wikibase.getEntity( countryEntityId );
	end
	
	if not countryEntity then
		return '<span class="country-name">' .. formatSnak(context, options, statement.mainsnak ) .. '</span>';
	end

	local endDateTimestamp = calculateEndDateTimestamp( context, options, statement );
	local boundaries = getTimeBoundariesFromProperties( context, {'P570', 'P577', 'P571'} );

	local countryOptions = mw.clone( options );
	if not countryOptions['text'] or countryOptions['text'] == '' then
		countryOptions['text'] = getLabel( context, countryEntity, boundaries );
	end

	local flag = getFlag( context, countryEntityId, endDateTimestamp );

	if ( flag ) then
		return flag .. '&nbsp;<span class="country-name">' .. formatSnak(context, countryOptions, statement.mainsnak ) .. '</span>';
	end

	return '<span class="country-name">' .. formatSnak(context, countryOptions, statement.mainsnak ) .. '</span>';
end

local function getEntityIdFromValue( value )
    return 'Q' .. value['numeric-id']
end

local function selectClaims(entity, propertySelector )

	local WDS = require('Module:WikidataSelectors')
	result = WDS.filter(entity.claims, propertySelector)

    if ( not result or #result == 0 ) then
    	return nil;
    end

    return result;
end

function formatSnak( context, args, snak)
	local hash = '';
	local mainSnakClass = '';
	if ( snak.hash ) then
		hash = ' data-wikidata-hash="' .. snak.hash .. '"';
	else
		mainSnakClass = ' wikidata-main-snak';
	end

	local before = '<span class="wikidata-snak ' .. mainSnakClass .. '"' .. hash .. '>'
	local after = '</span>'

    if snak.snaktype == 'somevalue' then
        return before .. after;
    elseif snak.snaktype == 'novalue' then
        return before .. after;
    elseif snak.snaktype == 'value' then
        return before .. formatDatavalue( context, args, snak.datavalue, snak.datatype ) .. after;
    end
end

--[[ 
  Функция для оформления значений (value)
  Подробнее о значениях  см. d:Wikidata:Glossary/ru

  Принимает: объект-значение и таблицу параметров,
  Возвращает: строку оформленного текста
]]
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;

    -- проверка на указание специализированных обработчиков в параметрах,
    -- переданных при вызове
    
    if datavalue.type == 'wikibase-entityid' then
    	-- идентификатор сущности
        context.formatValueDefault = function( context, options, value ) return formatEntityId( getEntityIdFromValue( value ), options ) end;
    end

    local functionToCall = context.formatValueDefault;
    return functionToCall( context, options, datavalue.value );
end

--[[ 
  Функция для оформления идентификатора сущности

  Принимает: строку индентификатора (типа Q42) и таблицу параметров,
  Возвращает: строку оформленного текста
]]
function formatEntityId( entityId, options )
    local label = nil;
	label = mw.wikibase.label( entityId );
    local link = mw.wikibase.sitelink( entityId )
    if link then
        if label then
            return '[[' .. link .. '|' .. label .. ']]'
        else
            return '[[' .. link .. ']]'
        end
    end

    if label then

		-- TODO: перенести до проверки на существование статьи
		local sup = '';
		if ( not options.format or options.format ~= 'text' )
				and entityId ~= 'Q6581072' and entityId ~= 'Q6581097' -- TODO: переписать на format=text
				then
			local lang = mw.language.getContentLanguage()
			sup = '<sup class="plainlinks noprint">[//www.wikidata.org/wiki/' .. entityId .. '?uselang=' .. lang:getCode() .. ' [d]]</sup>'
		end

        -- одноимённая статья уже существует - выводится текст и ссылка на ВД
        return '<span class="iw" data-title="' .. label .. '">' .. label
        	.. sup
        	.. '</span>'
    end
    return '';
end

function p.formatProperty( frame )
    local args = frame.args
    local entity = mw.wikibase.getEntityObject();
	args.entity = entity;

	-- create context
	local context = {
		entity = mw.wikibase.getEntityObject()}

	local claims = selectClaims(entity, args.property );

    local formattedClaims = {}

    for i, claim in ipairs(claims) do
        local formattedStatement = formatCountryClaimWithFlag( context, args, claim )
        formattedStatement = '<span class="wikidata-claim" data-wikidata-claim-id="' .. claim.id .. '">' .. formattedStatement .. '</span>'
            table.insert( formattedClaims, formattedStatement )
    end

	-- создание текстовой строки со списком оформленых заявлений из таблицы  
    local out = mw.text.listToText( formattedClaims, '<br />', '<br />' )
    if out ~= '' then
	    if args.before then
	    	out = args.before .. out
		end
	    if args.after then
	    	out = out .. args.after
		end
	end

    return out

end

return p

Dit Module "Wikidata-n" is uit Wikipedia. De lijst van zijn auteurs is te zien in zijn historische.