Модуль:Wikidata/Places: відмінності між версіями
Перейти до навігації
Перейти до пошуку
[перевірена версія] | [перевірена версія] |
Вилучено вміст Додано вміст
Shmurak (обговорення | внесок) на прохання NickK'а повернув адмінодиниці |
може через це створює помилку |
||
Рядок 1: | Рядок 1: | ||
local |
local categorizeByPlaceOfBirthAndDeath = true; |
||
local WDS = require( 'Module:WikidataSelectors' ); |
local WDS = require( 'Module:WikidataSelectors' ); |
||
local Flags = require( 'Module:Wikidata/Flags' ); |
local Flags = require( 'Module:Wikidata/Flags' ); |
||
local p = { |
local p = {}; |
||
local project = 'ukwiki'; |
|||
config = { |
|||
hideSameLabels = false, |
|||
hidePartOfLabels = false, |
|||
hideUnitsForCapitals = true, |
|||
reverseOrder = false, |
|||
} |
|||
}; |
|||
local function min( prev, next ) |
local function min( prev, next ) |
||
if prev == nil then |
if ( prev == nil ) then return next; |
||
elseif ( prev > next ) then return next; |
|||
else return prev; end |
|||
return next; |
|||
else |
|||
return prev; |
|||
end |
|||
end |
end |
||
local function max( prev, next ) |
local function max( prev, next ) |
||
if prev == nil then |
if ( prev == nil ) then return next; |
||
elseif ( prev < next ) then return next; |
|||
else return prev; end |
|||
return next; |
|||
else |
|||
return prev; |
|||
end |
|||
end |
end |
||
local function getTimeBoundariesFromProperty( context, propertyId ) |
local function getTimeBoundariesFromProperty( context, propertyId ) |
||
mw.log( 'Get time boundaries for ' .. propertyId .. '...'); |
|||
local dateClaims = WDS.filter( context.entity.claims, propertyId ); |
local dateClaims = WDS.filter( context.entity.claims, propertyId ); |
||
if not dateClaims or #dateClaims == 0 then |
if ( not dateClaims or #dateClaims == 0 ) then return nil; end |
||
mw.log( 'Get time boundaries for ' .. propertyId .. '... Got ' .. #dateClaims .. ' date claim(s)'); |
|||
return nil; |
|||
end |
|||
-- only support exact date so far, but need improvment |
-- only support exact date so far, but need improvment |
||
Рядок 42: | Рядок 29: | ||
local right = nil; |
local right = nil; |
||
for _, claim in pairs( dateClaims ) do |
for _, claim in pairs( dateClaims ) do |
||
if not claim.mainsnak then return nil; end |
if ( not claim.mainsnak ) then return nil; end |
||
local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak ); |
local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak ); |
||
if not boundaries then return nil; end |
if ( not boundaries ) then return nil; end |
||
left = min( left, boundaries[ 1 ] ); |
left = min( left, boundaries[ 1 ] ); |
||
right = max( right, boundaries[ 2 ] ); |
right = max( right, boundaries[ 2 ] ); |
||
end |
end |
||
if not left or not right then return nil; end |
if ( not left or not right ) then return nil; end |
||
mw.log( 'Time boundaries for ' .. propertyId .. ' are ' .. left .. ' and ' .. right ); |
|||
return { left, right }; |
return { left, right }; |
||
end |
end |
||
Рядок 69: | Рядок 57: | ||
local left = nil; |
local left = nil; |
||
local right = nil; |
local right = nil; |
||
if statement.qualifiers and statement.qualifiers[qualifierId] then |
if ( statement.qualifiers and statement.qualifiers[qualifierId] ) then |
||
for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do |
for _, qualifier in pairs( statement.qualifiers[qualifierId] ) do |
||
local boundaries = context.parseTimeBoundariesFromSnak( qualifier ); |
local boundaries = context.parseTimeBoundariesFromSnak( qualifier ); |
||
if not boundaries then return nil; end |
if ( not boundaries ) then return nil; end |
||
left = min( left, boundaries[1] ); |
left = min( left, boundaries[1] ); |
||
right = max( right, boundaries[2] ); |
right = max( right, boundaries[2] ); |
||
Рядок 78: | Рядок 66: | ||
end |
end |
||
if not left or not right then |
if ( not left or not right ) then |
||
return nil; |
return nil; |
||
end |
end |
||
Рядок 85: | Рядок 73: | ||
end |
end |
||
local function getParentsInBoundariesSnakImpl( context, |
local function getParentsInBoundariesSnakImpl( context, entity, boundaries, propertyIds ) |
||
local results = {}; |
local results = {}; |
||
Рядок 91: | Рядок 79: | ||
return results; |
return results; |
||
end |
end |
||
for _, propertyId in ipairs( propertyIds ) do |
|||
if (not string.match( propertyId, '^P%d+$' )) then error('Incorrect propertyId: ' + propertyId); end |
|||
local selector; |
|||
if (selectors ~= nil) then |
|||
selector = selectors[propertyId] or propertyId; |
|||
else |
|||
selector = propertyId; |
|||
end |
|||
if entity.claims then |
|||
local entityClaims = {}; |
|||
for _, propertyId in ipairs( propertyIds ) do |
|||
local filteredClaims = WDS.filter( entity.claims, propertyId .. '[rank:preferred, rank:normal]' ); |
|||
if filteredClaims then |
|||
local filteredClaims = WDS.filter( entityClaims, selector .. '[rank:preferred, rank:normal]' ); |
|||
for _, claim in pairs( filteredClaims ) do |
|||
if not boundaries or not propertyIds or #propertyIds == 0 then |
|||
for _, claim in pairs( filteredClaims ) do |
|||
if not boundaries or not propertyIds or #propertyIds == 0 then |
|||
table.insert( results, claim.mainsnak ); |
|||
else |
|||
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 ); |
table.insert( results, claim.mainsnak ); |
||
else |
|||
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 |
end |
||
end |
end |
||
end |
|||
if #results > 0 then |
if #results > 0 then |
||
break; |
break; |
||
end |
|||
end |
end |
||
end |
end |
||
Рядок 130: | Рядок 108: | ||
end |
end |
||
local function getParentsInBoundariesSnak( context, |
local function getParentsInBoundariesSnak( context, entity, boundaries ) |
||
if not |
if ( not entity ) then error('entity must be specified'); end |
||
if type( |
if ( type(entity) ~= 'table' ) then error('entity must be table'); end |
||
if not boundaries then error('boundaries must be specified'); end |
if ( not boundaries ) then error('boundaries must be specified'); end |
||
if type(boundaries) ~= 'table' then error('boundaries must be table'); end |
if ( type(boundaries) ~= 'table' ) then error('boundaries must be table'); end |
||
local results = getParentsInBoundariesSnakImpl( context, |
local results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {'P17'} ) -- country |
||
if not results or #results == 0 then |
|||
results = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P17'} ) -- country |
|||
end |
|||
for r, result in pairs( results ) do |
for r, result in pairs( results ) do |
||
Рядок 146: | Рядок 121: | ||
end |
end |
||
local resultId = result.datavalue.value.id; |
local resultId = result.datavalue.value.id; |
||
if resultId == |
if ( resultId == entity.id ) then |
||
return nil; |
return nil; |
||
end |
end |
||
Рядок 168: | Рядок 143: | ||
local isCountry = false; |
local isCountry = false; |
||
local isUnion = false; |
local isUnion = false; |
||
if |
if ( entity |
||
entity.claims |
and entity.claims |
||
entity.claims.P31 |
and entity.claims.P31 ) then |
||
then |
|||
for c, claim in pairs( entity.claims.P31 ) do |
for c, claim in pairs( entity.claims.P31 ) do |
||
if |
if ( claim |
||
claim.mainsnak |
and claim.mainsnak |
||
claim.mainsnak.datavalue |
and claim.mainsnak.datavalue |
||
claim.mainsnak.datavalue.value |
and claim.mainsnak.datavalue.value |
||
claim.mainsnak.datavalue.value |
and claim.mainsnak.datavalue.value['numeric-id'] ) then |
||
local typeId = 'Q' .. claim.mainsnak.datavalue.value['numeric-id']; |
|||
then |
|||
isCountry = isCountry or countries[typeId]; |
|||
local typeId = claim.mainsnak.datavalue.value.id; |
|||
isUnion = isUnion or unions[typeId]; |
|||
isUnion = isUnion or unions[ typeId ]; |
|||
end |
end |
||
end |
end |
||
Рядок 188: | Рядок 161: | ||
end |
end |
||
local function isPartOfNext( |
local function isPartOfNext(prevLabel, nextLabel) |
||
return ( |
return (mw.ustring.len(prevLabel) > mw.ustring.len(nextLabel)) |
||
and ( |
and (mw.ustring.sub( prevLabel, mw.ustring.len(prevLabel) - mw.ustring.len(nextLabel) + 1 ) == nextLabel); |
||
end |
end |
||
Рядок 196: | Рядок 169: | ||
function p.formatPlaceWithQualifiers( context, options, statement ) |
function p.formatPlaceWithQualifiers( context, options, statement ) |
||
local property = mw.ustring.upper( options.property ); |
local property = mw.ustring.upper( options.property ); |
||
mw.log( 'formatPlaceWithQualifiers(..., ' .. property .. ')'); |
|||
local actualDateBoundariesProperties = nil; |
|||
if property == 'P19' then actualDateBoundariesProperties = {'P569','P570'}; end |
|||
if property == 'P20' then actualDateBoundariesProperties = {'P570','P569'}; end |
|||
if property == 'P119' then actualDateBoundariesProperties = {'P570','P569'}; end |
|||
local boundaries = nil; |
|||
if actualDateBoundariesProperties ~= nil then |
|||
boundaries = getTimeBoundariesFromProperties( context, actualDateBoundariesProperties ); |
|||
end |
|||
local entriesToLookupCategory = {}; |
local entriesToLookupCategory = {}; |
||
Рядок 212: | Рядок 176: | ||
local result = ''; |
local result = ''; |
||
local baseResult = context.formatSnak( options, statement.mainsnak, circumstances ); |
local baseResult = context.formatSnak( options, statement.mainsnak, circumstances ); |
||
if not baseResult then |
|||
return nil; |
|||
end |
|||
insertFromSnak( statement.mainsnak, entriesToLookupCategory ) |
insertFromSnak( statement.mainsnak, entriesToLookupCategory ) |
||
local hasAdditionalQualifiers = false; |
local hasAdditionalQualifiers = false; |
||
if statement.qualifiers then |
if ( statement.qualifiers ) then |
||
--parent divisions |
|||
if statement.qualifiers.P131 then |
|||
for i, qualifier in ipairs( statement.qualifiers.P131 ) do |
|||
local parentOptions = context.cloneOptions( options ); |
|||
local qualifierEntityId = qualifier.datavalue.value.id; |
|||
parentOptions['text'] = getLabel( context, qualifierEntityId, boundaries ); |
|||
local link = context.formatSnak( parentOptions, qualifier ); |
|||
if p.config.reverseOrder then |
|||
result = link .. ', ' .. result; |
|||
else |
|||
result = result .. ', ' .. link; |
|||
end |
|||
insertFromSnak( qualifier, entriesToLookupCategory ) |
|||
hasAdditionalQualifiers = true; |
|||
end |
|||
end |
|||
--country |
--country |
||
if statement.qualifiers.P17 then |
if ( statement.qualifiers.P17 ) then |
||
for i, qualifier in ipairs( statement.qualifiers.P17 ) do |
for i, qualifier in ipairs( statement.qualifiers.P17 ) do |
||
result = result .. ', ' .. context.formatSnak( options, qualifier ); |
|||
local qualifierEntityId = qualifier.datavalue.value.id; |
|||
parentOptions[ 'text' ] = getLabel( context, qualifierEntityId, boundaries ); |
|||
local link = context.formatSnak( parentOptions, qualifier ); |
|||
if p.config.reverseOrder then |
|||
result = link .. ', ' .. result; |
|||
else |
|||
result = result .. ', ' .. link; |
|||
end |
|||
insertFromSnak( qualifier, entriesToLookupCategory ) |
insertFromSnak( qualifier, entriesToLookupCategory ) |
||
hasAdditionalQualifiers = true; |
hasAdditionalQualifiers = true; |
||
Рядок 257: | Рядок 190: | ||
end |
end |
||
if statement.mainsnak |
if ( statement.mainsnak |
||
statement.mainsnak.datavalue |
and statement.mainsnak.datavalue |
||
statement.mainsnak.datavalue.value |
and statement.mainsnak.datavalue.value |
||
statement.mainsnak.datavalue.value |
and statement.mainsnak.datavalue.value['numeric-id'] ) then |
||
local entity = mw.wikibase.getEntity( 'Q' .. statement.mainsnak.datavalue.value['numeric-id'] ); |
|||
then |
|||
local entityId = statement.mainsnak.datavalue.value.id; |
|||
local parentSnaks = { statement.mainsnak }; |
local parentSnaks = { statement.mainsnak }; |
||
local |
local parentEntities = { entity }; |
||
local actualDateBoundariesProperty = nil; |
|||
if actualDateBoundariesProperties ~= nil then |
|||
if ( property == 'P19' ) then actualDateBoundariesProperty = 'P569'; end |
|||
local filterCapitalOf = { |
|||
if ( property == 'P20' ) then actualDateBoundariesProperty = 'P570'; end |
|||
[ entityId ] = getParentsInBoundariesSnakImpl( context, entityId, boundaries, {'P1376'} ) |
|||
if ( property == 'P119' ) then actualDateBoundariesProperty = 'P570'; end |
|||
}; |
|||
if ( actualDateBoundariesProperty ~= nil ) then |
|||
if boundaries then |
|||
local boundaries = getTimeBoundariesFromProperty( context, actualDateBoundariesProperty ); |
|||
local entityOptions = context.cloneOptions( options ); |
|||
if ( boundaries ) then |
|||
local entityOptions = options; |
|||
-- local entityOptions = mw.clone( options ); |
|||
entityOptions['text'] = getLabel( context, entity, boundaries ); |
|||
baseResult = context.formatSnak( entityOptions, statement.mainsnak, circumstances ); |
baseResult = context.formatSnak( entityOptions, statement.mainsnak, circumstances ); |
||
local |
local parent = entity; |
||
while |
while ( parent ~= nil ) do |
||
-- get parent |
-- get parent |
||
local newParentSnaks = getParentsInBoundariesSnak( context, |
local newParentSnaks = getParentsInBoundariesSnak( context, parent, boundaries ); |
||
if not newParentSnaks or #newParentSnaks == 0 then |
if ( not newParentSnaks or #newParentSnaks == 0 ) then |
||
parent = nil; |
|||
elseif #newParentSnaks == 1 then |
elseif ( #newParentSnaks == 1 ) then |
||
local parentSnak = newParentSnaks[ |
local parentSnak = newParentSnaks[1]; |
||
parent = mw.wikibase.getEntity( 'Q' .. parentSnak.datavalue.value['numeric-id'] ); |
|||
table.insert( parentSnaks, parentSnak ); |
table.insert( parentSnaks, parentSnak ); |
||
table.insert( |
table.insert( parentEntities, parent ); |
||
filterCapitalOf[ parentId ] = getParentsInBoundariesSnakImpl( context, parentId, boundaries, { 'P1376' } ); |
|||
else |
else |
||
parent = nil; |
|||
result = result .. '[[Категорія:Вікіпедія:Сторінки з неоднозначними геоланками]]'; |
|||
end |
end |
||
end |
end |
||
if not hasAdditionalQualifiers then |
if ( not hasAdditionalQualifiers ) then |
||
for i |
for i=2,#parentSnaks,1 do |
||
local parentSnak = parentSnaks[ |
local parentSnak = parentSnaks[i]; |
||
insertFromSnak( parentSnak, entriesToLookupCategory ) |
insertFromSnak( parentSnak, entriesToLookupCategory ) |
||
end |
end |
||
end |
end |
||
-- mw.logObject( parentSnaks ); |
|||
do |
do |
||
local i = #parentSnaks; |
local i = #parentSnaks; |
||
while i > 1 do |
while ( i > 1 ) do |
||
local |
local prevEntity = parentEntities[i - 1]; |
||
-- TODO: use English labels, if there is no current language labels |
-- TODO: use English labels, if there is no current language labels |
||
local prevLabel = getLabel( context, |
local prevLabel = getLabel( context, prevEntity, boundaries ) or ''; |
||
local |
local nextEntity = parentEntities[i]; |
||
local nextLabel = getLabel( context, |
local nextLabel = getLabel( context, nextEntity, boundaries ) or ''; |
||
if |
if ( prevLabel == nextLabel ) then |
||
-- do not output same label twice (NY, NY, USA) |
-- do not output same label twice (NY, NY, USA) |
||
table.remove( parentSnaks, i ); |
table.remove( parentSnaks, i ); |
||
table.remove( |
table.remove( parentEntities, i ); |
||
elseif |
elseif ( isPartOfNext( prevLabel, ' ' .. nextLabel ) ) then |
||
-- do not output same label if it's part of previos |
-- do not output same label if it's part of previos |
||
table.remove( parentSnaks, i - 1 ); |
table.remove( parentSnaks, i - 1 ); |
||
table.remove( |
table.remove( parentEntities, i - 1 ); |
||
elseif p.config and p.config.hideUnitsForCapitals == true then |
|||
-- do not ouput items whose capital is the first item |
|||
local capitalId = nil; |
|||
for _capitalId, capitalSnaks in pairs( filterCapitalOf ) do |
|||
if #capitalSnaks > 0 then |
|||
for __, capitalSnak in pairs( capitalSnaks ) do |
|||
if parentSnaks[ i ].datavalue.value.id == capitalSnak.datavalue.value.id then |
|||
capitalId = _capitalId; |
|||
break; |
|||
end |
|||
end |
|||
end |
|||
end |
|||
if capitalId ~= nil then |
|||
if i == #parentSnaks then |
|||
i = i - 1; |
|||
end |
|||
while i > 1 and parentEntityIds[ i ] ~= capitalId do |
|||
table.remove( parentSnaks, i ); |
|||
table.remove( parentEntityIds, i ); |
|||
i = i - 1; |
|||
end |
|||
end |
|||
end |
end |
||
i = i - 1; |
i = i - 1; |
||
Рядок 344: | Рядок 256: | ||
end |
end |
||
if isSkipTopLevel( |
if ( isSkipTopLevel( parentEntities[ #parentEntities ] ) ) then |
||
table.remove( parentSnaks, # |
table.remove( parentSnaks, #parentEntities ); |
||
table.remove( |
table.remove( parentEntities, #parentEntities ); |
||
end |
end |
||
if not hasAdditionalQualifiers then |
if ( not hasAdditionalQualifiers ) then |
||
for i |
for i=2,#parentSnaks,1 do |
||
local parentSnak = parentSnaks[ |
local parentSnak = parentSnaks[i]; |
||
local parentOptions = |
local parentOptions = options; |
||
parentOptions |
-- local parentOptions = mw.clone( options ); |
||
parentOptions['text'] = getLabel( context, parentEntities[i], boundaries ); |
|||
result = result .. ', ' .. context.formatSnak( parentOptions, parentSnak ); |
|||
if p.config.reverseOrder then |
|||
result = context.formatSnak( parentOptions, parentSnak ) .. ', ' .. result; |
|||
else |
|||
result = result .. ', ' .. context.formatSnak( parentOptions, parentSnak ); |
|||
end |
|||
end |
end |
||
end |
end |
||
Рядок 367: | Рядок 276: | ||
end |
end |
||
if options[ |
if ( options['thisLocationOnly'] ) then |
||
result = baseResult .. context.formatRefs( options, statement ); |
result = baseResult .. context.formatRefs( options, statement ); |
||
elseif p.config.reverseOrder then |
|||
result = result .. baseResult .. context.formatRefs( options, statement ); |
|||
else |
else |
||
result = baseResult .. result .. context.formatRefs( options, statement ); |
result = baseResult .. result .. context.formatRefs( options, statement ); |
||
end |
end |
||
if ( categorizeByPlaceOfBirthAndDeath ) then |
|||
if categorizeByPlace then |
|||
if property == 'P19' then result = result .. getCategory( 'P1464', entriesToLookupCategory ); end |
if ( property == 'P19' ) then result = result .. getCategory( 'P1464', entriesToLookupCategory ); end |
||
if property == 'P20' then result = result .. getCategory( 'P1465', entriesToLookupCategory ); end |
if ( property == 'P20' ) then result = result .. getCategory( 'P1465', entriesToLookupCategory ); end |
||
if property == 'P119' then result = result .. getCategory( 'P1791', entriesToLookupCategory ); end |
if ( property == 'P119' ) then result = result .. getCategory( 'P1791', entriesToLookupCategory ); end |
||
end |
end |
||
Рядок 386: | Рядок 293: | ||
-- append entity id from snak to result |
-- append entity id from snak to result |
||
function insertFromSnak( snak, result ) |
function insertFromSnak( snak, result ) |
||
if not |
if ( not categorizeByPlaceOfBirthAndDeath ) then |
||
return; |
return; |
||
end |
end |
||
if snak |
if ( snak |
||
snak.datavalue |
and snak.datavalue |
||
snak.datavalue.type == 'wikibase-entityid' |
and snak.datavalue.type == 'wikibase-entityid' |
||
snak.datavalue.value |
and snak.datavalue.value |
||
snak.datavalue.value[ |
and snak.datavalue.value['entity-type'] == 'item' ) then |
||
table.insert( result, 'Q' .. snak.datavalue.value['numeric-id'] ); |
|||
then |
|||
table.insert( result, snak.datavalue.value.id ); |
|||
end |
end |
||
end |
end |
||
function getCategory( |
function getCategory( propertyToSearch, entriesToLookupCategoryFor ) |
||
for _, placeId in pairs( entriesToLookupCategoryFor ) do |
for _, placeId in pairs( entriesToLookupCategoryFor ) do |
||
local |
local placeEntity = mw.wikibase.getEntity( placeId ); |
||
local claims = WDS.filter( placeEntity.claims, propertyToSearch ); |
|||
if claims then |
if ( claims ) then |
||
for _, claim in pairs( claims ) do |
for _, claim in pairs( claims ) do |
||
if claim.mainsnak |
if ( claim.mainsnak |
||
claim.mainsnak |
and claim.mainsnak |
||
claim.mainsnak.datavalue |
and claim.mainsnak.datavalue |
||
claim.mainsnak.datavalue.type == |
and claim.mainsnak.datavalue.type == "wikibase-entityid" ) then |
||
local catEntityId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"]; |
|||
then |
|||
local |
local catEntity = mw.wikibase.getEntity( catEntityId ); |
||
if ( catEntity and catEntity.sitelinks and catEntity.sitelinks[project] and catEntity.sitelinks[project].title ) then |
|||
local catSitelink = mw.wikibase.getSitelink(catEntityId); |
|||
return '[[' .. catEntity.sitelinks[project].title .. ']]'; |
|||
if (catSitelink) then |
|||
return '[[' .. catSitelink .. ']]'; |
|||
end |
end |
||
end |
end |
||
Рядок 421: | Рядок 327: | ||
return ''; |
return ''; |
||
end |
end |
||
local historicNamesProperties = { 'P1813', 'P1448', 'P1705' }; |
|||
local langCode = mw.language.getContentLanguage():getCode(); |
|||
local historicNamesPropertySelectors = { |
|||
P1813 = 'P1813[language:' .. langCode .. ']', |
|||
P1448 = 'P1448[language:' .. langCode .. ']', |
|||
P1705 = 'P1705[language:' .. langCode .. ']' |
|||
}; |
|||
-- get current of historic name of place |
-- get current of historic name of place |
||
function getLabel( context, |
function getLabel( context, entity, boundaries ) |
||
if not |
if not entity then |
||
return nil; |
return nil; |
||
end |
end |
||
if (type(entityId) ~= 'string') then error('incorrect type of entityId argument'); end; |
|||
local lang = mw.language.getContentLanguage(); |
|||
local langCode = lang:getCode(); |
|||
-- name from label |
-- name from label |
||
-- TODO: lang:getFallbackLanguages() |
|||
local label = mw.wikibase.getLabel( entityId ); |
|||
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 |
-- name from properties |
||
local results = getParentsInBoundariesSnakImpl( context, |
local results = getParentsInBoundariesSnakImpl( context, entity, boundaries, { |
||
'P1813[language:' .. langCode .. ']', |
|||
historicNamesProperties, historicNamesPropertySelectors); |
|||
'P1448[language:' .. langCode .. ']', |
|||
'P1705[language:' .. langCode .. ']' |
|||
} ); |
|||
for r, result in pairs( results ) do |
for r, result in pairs( results ) do |
||
if result.datavalue |
if result.datavalue |
||
result.datavalue.value |
and result.datavalue.value |
||
result.datavalue.value.text |
and result.datavalue.value.text then |
||
then |
|||
label = result.datavalue.value.text; |
label = result.datavalue.value.text; |
||
break; |
break; |
||
Рядок 462: | Рядок 370: | ||
local function calculateEndDateTimestamp( context, options, statement ) |
local function calculateEndDateTimestamp( context, options, statement ) |
||
if not context then error( |
if (not context) then error('context not specified') end; |
||
if not options then error( |
if (not options) then error('options not specified') end; |
||
if not options.entity then error( |
if (not options.entity) then error('options.entity missing') end; |
||
if not statement then error( |
if (not statement) then error('statement not specified') end; |
||
if statement.qualifiers and statement.qualifiers.P582 then |
if ( statement.qualifiers and statement.qualifiers.P582 ) then |
||
for i, qualifier in ipairs( |
for i, qualifier in ipairs(statement.qualifiers.P582 ) do |
||
local parsedTime = context.parseTimeFromSnak( qualifier ); |
local parsedTime = context.parseTimeFromSnak( qualifier ); |
||
if parsedTime then |
if ( parsedTime ) then |
||
return parsedTime; |
return parsedTime; |
||
end |
end |
||
Рядок 477: | Рядок 385: | ||
-- check death day... do we have it at all? |
-- check death day... do we have it at all? |
||
for h, propertyId in pairs( { "P570", "P577", " |
for h, propertyId in pairs( { "P570", "P577", "P571" } ) do |
||
local dateClaims = context.selectClaims( options, propertyId ); |
local dateClaims = context.selectClaims( options, propertyId ); |
||
if dateClaims then |
if ( dateClaims ) then |
||
for i, statement in ipairs( dateClaims ) do |
for i, statement in ipairs( dateClaims ) do |
||
local parsedTime = context.parseTimeFromSnak( statement.mainsnak ); |
local parsedTime = context.parseTimeFromSnak( statement.mainsnak ); |
||
if parsedTime then |
if ( parsedTime ) then |
||
return parsedTime; |
return parsedTime; |
||
end |
end |
||
Рядок 496: | Рядок 404: | ||
function p.formatCountryClaimWithFlag( context, options, statement ) |
function p.formatCountryClaimWithFlag( context, options, statement ) |
||
if not context then error('context not specified') end; |
if (not context) then error('context not specified') end; |
||
if not options then error('options 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 options.entity) then error('options.entity is missing') end; |
||
if not statement then error('statement not specified') end; |
if (not statement) then error('statement not specified') end; |
||
local countryEntityId = nil; |
|||
if not statement.mainsnak or |
|||
local countryEntity = nil; |
|||
not statement.mainsnak.datavalue or |
|||
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 ); |
|||
then |
|||
local result = context.formatStatementDefault( context, options, statement ); |
|||
if not result then |
|||
return ''; |
|||
end |
|||
return '<span class="country-name">' .. result .. '</span>'; |
|||
end |
end |
||
if not countryEntity then |
|||
local countryEntityId = statement.mainsnak.datavalue.value.id; |
|||
return '<span class="country-name">' .. context.formatStatementDefault( context, options, statement ) .. '</span>'; |
|||
end |
|||
local endDateTimestamp = calculateEndDateTimestamp( context, options, statement ); |
local endDateTimestamp = calculateEndDateTimestamp( context, options, statement ); |
||
local boundaries = getTimeBoundariesFromProperties( context, {'P570', 'P577', 'P571'} ); |
local boundaries = getTimeBoundariesFromProperties( context, {'P570', 'P577', 'P571'} ); |
||
local countryOptions = |
local countryOptions = mw.clone( options ); |
||
if not countryOptions['text'] or countryOptions['text'] == '' then |
if not countryOptions['text'] or countryOptions['text'] == '' then |
||
countryOptions['text'] = getLabel( context, |
countryOptions['text'] = getLabel( context, countryEntity, boundaries ); |
||
end |
end |
||
local flag = Flags.getFlag( context, countryEntityId, endDateTimestamp ); |
local flag = Flags.getFlag( context, countryEntityId, endDateTimestamp ); |
||
if flag then |
if ( flag ) then |
||
return flag .. ' <span class="country-name">' .. |
return flag .. ' <span class="country-name">' .. context.formatStatementDefault( context, countryOptions, statement ) .. '</span>'; |
||
context.formatStatementDefault( context, countryOptions, statement ) .. |
|||
'</span>'; |
|||
end |
end |
||
return '<span class="country-name">' .. |
return '<span class="country-name">' .. context.formatStatementDefault( context, countryOptions, statement ) .. '</span>'; |
||
context.formatStatementDefault( context, countryOptions, statement ) .. |
|||
'</span>'; |
|||
end |
end |
||
Версія за 07:48, 10 вересня 2018
Документація модуля[перегляд] [редагувати] [історія] [очистити кеш]
Цей модуль залежить від наступних модулів: |
{{Модуль:Wikidata/Places}} (обг. · викор. · ред.) містить функції форматування для Властивостей (claims), які є посиланнями на географічні сутності (зазвичай — адміністративні одиниці).
- formatPlaceWithQualifiers ← {{wikidata/p19}}
- formatPlaceWithQualifiers ← {{wikidata/p20}}
Вызов всех функций данного шаблона осуществляется из шаблона {{wikidata}}. Функции модуля нельзя вызывать напрямую — они передаются в виде аргументов из соответствующих связанных шаблонов (и только из них, в другие шаблоны их также вставлять не нужно).
formatPlaceWithQualifiers
...
Категорії підтримки
Документація вище включена з Модуль:Wikidata/Places/документація. (ред. | історія) Дописувачі можуть експериментувати на підсторінках пісочниця (створити | дзеркало) та тести (створити) цього шаблону. Будь ласка, додавайте категорії до підсторінки /Places/документація. Підсторінки цієї сторінки. |
local categorizeByPlaceOfBirthAndDeath = true;
local WDS = require( 'Module:WikidataSelectors' );
local Flags = require( 'Module:Wikidata/Flags' );
local p = {};
local project = 'ukwiki';
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;
for _, claim in pairs( dateClaims ) do
if ( not claim.mainsnak ) then return nil; end
local boundaries = context.parseTimeBoundariesFromSnak( claim.mainsnak );
if ( not boundaries ) then return nil; end
left = min( left, boundaries[ 1 ] );
right = max( right, boundaries[ 2 ] );
end
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 not propertyIds or #propertyIds == 0 then
return results;
end
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
if not boundaries or not propertyIds or #propertyIds == 0 then
table.insert( results, claim.mainsnak );
else
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
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, {'P17'} ) -- country
for r, result in pairs( results ) do
if result.snaktype ~= 'value' then
return nil;
end
local resultId = result.datavalue.value.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
--Property:P19, Property:P20, Property:P119
function p.formatPlaceWithQualifiers( context, options, statement )
local property = mw.ustring.upper( options.property );
mw.log( 'formatPlaceWithQualifiers(..., ' .. property .. ')');
local entriesToLookupCategory = {};
local circumstances = context.getSourcingCircumstances( statement );
local result = '';
local baseResult = context.formatSnak( options, statement.mainsnak, circumstances );
insertFromSnak( statement.mainsnak, entriesToLookupCategory )
local hasAdditionalQualifiers = false;
if ( statement.qualifiers ) then
--country
if ( statement.qualifiers.P17 ) then
for i, qualifier in ipairs( statement.qualifiers.P17 ) do
result = result .. ', ' .. context.formatSnak( options, qualifier );
insertFromSnak( qualifier, entriesToLookupCategory )
hasAdditionalQualifiers = true;
end
end
end
if ( statement.mainsnak
and statement.mainsnak.datavalue
and statement.mainsnak.datavalue.value
and statement.mainsnak.datavalue.value['numeric-id'] ) then
local entity = mw.wikibase.getEntity( 'Q' .. statement.mainsnak.datavalue.value['numeric-id'] );
local parentSnaks = { statement.mainsnak };
local parentEntities = { entity };
local actualDateBoundariesProperty = nil;
if ( property == 'P19' ) then actualDateBoundariesProperty = 'P569'; end
if ( property == 'P20' ) then actualDateBoundariesProperty = 'P570'; end
if ( property == 'P119' ) then actualDateBoundariesProperty = 'P570'; end
if ( actualDateBoundariesProperty ~= nil ) then
local boundaries = getTimeBoundariesFromProperty( context, actualDateBoundariesProperty );
if ( boundaries ) then
local entityOptions = options;
-- local entityOptions = mw.clone( options );
entityOptions['text'] = getLabel( context, entity, boundaries );
baseResult = context.formatSnak( entityOptions, statement.mainsnak, circumstances );
local parent = entity;
while ( parent ~= nil ) do
-- get parent
local newParentSnaks = getParentsInBoundariesSnak( context, parent, boundaries );
if ( not newParentSnaks or #newParentSnaks == 0 ) then
parent = nil;
elseif ( #newParentSnaks == 1 ) then
local parentSnak = newParentSnaks[1];
parent = mw.wikibase.getEntity( 'Q' .. parentSnak.datavalue.value['numeric-id'] );
table.insert( parentSnaks, parentSnak );
table.insert( parentEntities, parent );
else
parent = nil;
result = result .. '[[Категорія:Вікіпедія:Сторінки з неоднозначними геоланками]]';
end
end
if ( not hasAdditionalQualifiers ) then
for i=2,#parentSnaks,1 do
local parentSnak = parentSnaks[i];
insertFromSnak( parentSnak, entriesToLookupCategory )
end
end
-- mw.logObject( parentSnaks );
do
local i = #parentSnaks;
while ( i > 1 ) do
local prevEntity = parentEntities[i - 1];
-- TODO: use English labels, if there is no current language labels
local prevLabel = getLabel( context, prevEntity, boundaries ) or '';
local nextEntity = parentEntities[i];
local nextLabel = getLabel( context, nextEntity, boundaries ) or '';
if ( prevLabel == nextLabel ) then
-- do not output same label twice (NY, NY, USA)
table.remove( parentSnaks, i );
table.remove( parentEntities, i );
elseif ( isPartOfNext( prevLabel, ' ' .. nextLabel ) ) then
-- do not output same label if it's part of previos
table.remove( parentSnaks, i - 1 );
table.remove( parentEntities, i - 1 );
end
i = i - 1;
end
end
if ( isSkipTopLevel( parentEntities[ #parentEntities ] ) ) then
table.remove( parentSnaks, #parentEntities );
table.remove( parentEntities, #parentEntities );
end
if ( not hasAdditionalQualifiers ) then
for i=2,#parentSnaks,1 do
local parentSnak = parentSnaks[i];
local parentOptions = options;
-- local parentOptions = mw.clone( options );
parentOptions['text'] = getLabel( context, parentEntities[i], boundaries );
result = result .. ', ' .. context.formatSnak( parentOptions, parentSnak );
end
end
end
end
end
if ( options['thisLocationOnly'] ) then
result = baseResult .. context.formatRefs( options, statement );
else
result = baseResult .. result .. context.formatRefs( options, statement );
end
if ( categorizeByPlaceOfBirthAndDeath ) then
if ( property == 'P19' ) then result = result .. getCategory( 'P1464', entriesToLookupCategory ); end
if ( property == 'P20' ) then result = result .. getCategory( 'P1465', entriesToLookupCategory ); end
if ( property == 'P119' ) then result = result .. getCategory( 'P1791', entriesToLookupCategory ); end
end
return result;
end
-- append entity id from snak to result
function insertFromSnak( snak, result )
if ( not categorizeByPlaceOfBirthAndDeath ) then
return;
end
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
function getCategory( propertyToSearch, entriesToLookupCategoryFor )
for _, placeId in pairs( entriesToLookupCategoryFor ) do
local placeEntity = mw.wikibase.getEntity( placeId );
local claims = WDS.filter( placeEntity.claims, propertyToSearch );
if ( claims ) then
for _, claim in pairs( claims ) do
if ( claim.mainsnak
and claim.mainsnak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.type == "wikibase-entityid" ) then
local catEntityId = 'Q' .. claim.mainsnak.datavalue.value["numeric-id"];
local catEntity = mw.wikibase.getEntity( catEntityId );
if ( catEntity and catEntity.sitelinks and catEntity.sitelinks[project] and catEntity.sitelinks[project].title ) then
return '[[' .. catEntity.sitelinks[project].title .. ']]';
end
end
end
end
end
return '';
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
p.getLabel = getLabel;
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
-- check death day... do we have it at all?
for h, propertyId in pairs( { "P570", "P577", "P571" } ) do
local dateClaims = context.selectClaims( options, propertyId );
if ( dateClaims ) then
for i, statement in ipairs( dateClaims ) do
local parsedTime = context.parseTimeFromSnak( statement.mainsnak );
if ( parsedTime ) then
return parsedTime;
end
end
end
end
-- TODO: check other "end" properties
-- no death day
return os.time() * 1000;
end
function p.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">' .. context.formatStatementDefault( context, options, statement ) .. '</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 = Flags.getFlag( context, countryEntityId, endDateTimestamp );
if ( flag ) then
return flag .. ' <span class="country-name">' .. context.formatStatementDefault( context, countryOptions, statement ) .. '</span>';
end
return '<span class="country-name">' .. context.formatStatementDefault( context, countryOptions, statement ) .. '</span>';
end
return p;