Module:Universal infocard
Warning: | This page is shared between multiple wikis. All changes to this page will be automatically copied to all wikis listed in the left side bar. To avoid unnecessary page regeneration and server load, changes should be tested on the page's sandbox. |
--[[
Lua code for universal infocard.
]]
local isConfig, config = pcall( require, 'Module:Universal infocard/config' );
if isConfig == false then
config = {
skipPropertyIds = {
P31 = true,
P279 = true,
}
};
end
local p = {};
local lang = mw.getContentLanguage();
local entityId = nil;
-- CSS classes.
local classes = {};
if config and config.classes then
for key, value in pairs( config.classes ) do
classes[ key ] = value;
end
end
function getClassString( type )
local class;
if classes[type] then
class = classes[type];
elseif type ~= '' then
class = 'infobox-' .. type;
else
class = 'infobox';
end
if class == '' then
return '';
end
return ' class="'.. class .. '"';
end
function getTemplate( propertyId )
if config and config.templates then
if config.templates[ propertyId ] then
return config.templates[ propertyId ];
elseif string.match( propertyId, '^title_Q%d+$' ) then
return nil; -- hack for getTitleTemplate()
end
end
if propertyId == 'title' then
return '{{PAGENAME}}';
end
if propertyId == 'map' then
return getMap;
end
if config and config.templates and config.templates.default then
return config.templates.default;
end
if string.match( propertyId, '^P%d+$' ) then
return '#statements:' .. propertyId;
end
return nil;
end
--[[
Checks entity classes and tries to return a custom template, if one exists.
Otherwise, returns the base template for the title.
]]
function getTitleTemplate( claims )
if not claims then
return getTemplate( 'title' );
end
for _, claim in pairs( claims ) do
if claim.mainsnak
and claim.mainsnak.datavalue
and claim.mainsnak.datavalue.value
and claim.mainsnak.datavalue.value.id
and claim.mainsnak.datavalue.value.id == itemId then
local template = getTemplate( 'title:' .. itemId );
if template then
return template;
end;
end
end
return getTemplate( 'title' );
end
function expandTemplate( frame, title, args )
if not title then
return '';
elseif type( title ) == 'function' then
args.frame = frame;
return title( args )
elseif type( title ) == 'string' then
if string.match( title, '^#' ) then
return frame:callParserFunction{ name = title, args = args };
elseif string.match( title, '^{' ) then
return frame:preprocess( title );
else
return frame:expandTemplate{ title = title, args = args };
end
elseif type( title ) == 'table' then
local realTitle = title[ 1 ];
table.remove( title, 1 )
return expandTemplate( frame, realTitle, title )
end
end
function splitLine( value1, value2 )
local result = '';
if ( value1 and string.len( value1 ) ~= 0 ) or ( value2 and string.len( value2 ) ~= 0 ) then
result = '<tr>';
if ( value1 and string.len( value1 ) ~= 0 ) then
local colspan = '';
if ( not value2 or string.len( value2 ) == 0 ) then
colspan = 'colspan="2"';
end
result = result .. '<td ' .. colspan .. getClassString( 'split' ) .. '>';
result = result .. value1;
result = result .. '</td>';
end
if ( value2 and string.len( value2 ) ~= 0 ) then
local colspan = '';
if ( not value1 or string.len( value1 ) == 0 ) then
colspan = 'colspan="2"';
end
result = result .. '<td ' .. colspan .. getClassString( 'split' ) .. '>';
result = result .. value2;
result = result .. '</td>';
end
result = result .. '</tr>\n';
end
return result;
end
function getLine( value, class )
local result = '';
if ( value and string.len( value ) ~= 0 ) then
result = result .. '<tr><td colspan="2"'.. getClassString( class ) .. '>';
result = result .. value;
result = result .. '</td></tr>\n';
return result;
end
return result;
end
function getValue( label, value )
local result = '';
if ( value ~= nil and string.len( value ) ~= 0 ) then
if label then
result = result .. '<tr><th' .. getClassString( 'label' ) .. '>' .. label .. '</th>';
result = result .. '<td' .. getClassString( 'text' ) .. '>\n';
else
result = result .. '<tr><td colspan="2"' .. getClassString( 'text' ) .. '>';
end
result = result .. value;
result = result .. '</td></tr>\n';
return result;
end
return result;
end
function getMap( args )
local entityId = args.entityId or mw.wikibase.getEntityIdForCurrentPage();
local statements = mw.wikibase.getBestStatements( entityId, 'P625' );
if not statements or
not statements[ 1 ] or
not statements[ 1 ].mainsnak or
statements[ 1 ].mainsnak.snaktype ~= 'value' or
statements[ 1 ].mainsnak.datavalue.value.globe ~= 'http://www.wikidata.org/entity/Q2'
then
return '';
end
local coord = statements[ 1 ].mainsnak.datavalue.value;
local title = expandTemplate( args.frame, getTemplate( 'title' ), { from = entityId } );
local mapContent = [[ {
"type": "Feature",
"geometry": {
"type": "Point",
"coordinates": [
]] .. coord['longitude'] .. [[,
]] .. coord['latitude'] .. [[
]
},
"properties": {
"title": "]] .. title .. [[",
"marker-symbol": "star",
"marker-color": "#3366cc"
}
}, {
"type": "ExternalData",
"service": "geoline",
"ids": "]] .. entityId .. [[",
"properties": {
"stroke": "#FF9999"
}
}, {
"type": "ExternalData",
"service": "geoshape",
"ids": "]] .. entityId .. [[",
"properties": {
"fill": "#FF0000",
"fill-opacity": 0.1,
"stroke": "#FF9999"
}
} ]];
local mapWidth = 274;
local mapHeight = 250;
if config and config.map then
if config.map.width then
mapWidth = config.map.width;
end
if config.map.height then
mapHeight = config.map.height;
end
end
return args.frame:extensionTag{
name = 'mapframe',
content = '[' .. mapContent .. ']',
args = {
'frameless',
align = 'center',
latitude = coord['latitude'],
longitude = coord['longitude'],
zoom = 11,
width = mapWidth,
height = mapHeight,
}
};
end
function renderValue( frame, propertyId, args )
local tplArgs = { propertyId, from = entityId, nocat = frame.args['nocat'] };
if args then
local k = nil;
repeat
k = next( args, k );
if k then
tplArgs[ k ] = args[ k ];
end
until not k
end
return expandTemplate( frame, getTemplate( propertyId ), tplArgs );
end
-- Filter deprecated claims and returning only preferred ones if present.
function filterClaims( entity, propertyId )
if ( entity.claims == nil or entity.claims[ propertyId ] == nil ) then
return {};
end
local all = entity.claims[ propertyId ];
local normal = {};
local preferred = {};
for _, claim in pairs( all ) do
local rank = claim.rank or 'normal';
if ( rank == 'normal' ) then
table.insert( normal, claim );
end
if ( rank == 'preferred' ) then
table.insert( preferred, claim );
end
end
if ( #preferred > 0 ) then
return preferred;
end
return normal;
end
function propertyLabel( propertyId )
local label, labelLang = mw.wikibase.getLabelWithLang( propertyId );
label = lang:ucfirst( label );
if labelLang ~= lang:getCode() then
label = '[[d:Property:' .. propertyId .. '|' .. label .. ']]';
end
return label;
end
function simpleLabel( entityId )
local label = mw.wikibase.label( entityId );
label = lang:ucfirst( label );
return label;
end
function getErrorMessage( message )
local result = '<table cellspacing="2"' .. getClassString( 'error' ) .. '>\n';
result = result .. '<tr><td colspan="2">' .. message .. '</td></tr>\n';
result = result .. '</table>';
return result;
end
function p.render( frame )
local i18n_error_emptyWikidataEntity = '';
local i18n_error_noWikidataEntity = '';
if config and config.i18n and config.i18n.error then
if config.i18n.error.emptyWikidataEntity then
i18n_error_emptyWikidataEntity = config.i18n.error.emptyWikidataEntity;
end
if config.i18n.error.noWikidataEntity then
i18n_error_noWikidataEntity = config.i18n.error.noWikidataEntity;
end
end
local result = '<table cellspacing="2"' .. getClassString( '' );
if config and config.i18n and config.i18n.dataName then
result = result .. ' data-name="' .. config.i18n.dataName .. '"';
end
result = result .. '>\n';
local localImage = nil;
if ( frame ~= nil and frame:getParent() ~= nil ) then
local p_frame = frame:getParent();
if p_frame.args ~= nil then
-- image under FU only in local
localImage = p_frame.args.image;
if p_frame.args.from ~= nil and p_frame.args.from ~= '' then
entityId = p_frame.args.from;
elseif p_frame.args[ 1 ] ~= nil and string.gmatch( p_frame.args[ 1 ], '^Q\d+$' ) then
entityId = p_frame.args[ 1 ];
end
end
end
local wdStatus, entity = pcall( mw.wikibase.getEntity, entityId );
if wdStatus ~= true or entity == nil then
return getErrorMessage( i18n_error_noWikidataEntity );
elseif entity.claims == nil then
return getErrorMessage( i18n_error_emptyWikidataEntity );
end
-- TODO: Need to consider how to display class properties (P31, P279, P361, ...).
local skipPropertyIds = {};
if config.skipPropertyIds then
skipPropertyIds = mw.clone( config.skipPropertyIds );
end
local claims = entity.claims;
local order = mw.wikibase.getPropertyOrder() or {};
-- Header.
local entityLabel, entityLabelLang = entity:getLabelWithLang( lang:getCode() );
local label;
---- Name.
local titleTemplate = getTitleTemplate( claims.P31 );
if entityLabelLang == lang:getCode() then
label = expandTemplate( frame, titleTemplate, { wdLabel, from = entityId } );
else
label = expandTemplate( frame, titleTemplate, { from = entityId } );
end
result = result .. getLine( label, 'above' );
---- Original name.
if claims.P1559 ~= nil then
result = result .. getLine( expandTemplate( frame, getTemplate( 'P1559' ), { from = entityId } ), 'original' );
elseif claims.P1705 ~= nil then
result = result .. getLine( expandTemplate( frame, getTemplate( 'P1705' ), { from = entityId } ), 'original' );
end
---- Flag and COA.
if claims.P41 or claims.P94 then
local flag = nil;
local flagLabel = nil;
local coa = nil;
local coaLabel = nil;
if claims.P41 then
flag = renderValue( frame, 'P41' );
if claims.P163 then
flagLabel = renderValue( frame, 'P163', { text = simpleLabel( 'Q14660' ) } );
else
flagLabel = simpleLabel( 'Q14660' );
end
end
if claims.P94 then
coa = renderValue( frame, 'P94' );
if claims.P163 then
coaLabel = renderValue( frame, 'P237', { text = simpleLabel( 'Q14659' ) } );
else
coaLabel = simpleLabel( 'Q14659' );
end
end
result = result .. splitLine( flagLabel, coaLabel );
result = result .. splitLine( flag, coa );
end
-- Body.
local propertyIds = {};
for propertyId, claim in pairs( entity.claims ) do
table.insert( propertyIds, propertyId );
end
local orderedProperties = mw.wikibase.orderProperties( propertyIds )
local shownProperties = 0
for i, propertyId in ipairs( orderedProperties ) do
local propertyClaims = claims[ propertyId ];
if not skipPropertyIds[ propertyId ]
and propertyClaims
and propertyClaims[ 1 ]
and propertyClaims[ 1 ].mainsnak
and propertyClaims[ 1 ].mainsnak.datatype
and propertyClaims[ 1 ].mainsnak.datatype ~= 'external-id'
and propertyClaims[ 1 ].mainsnak.datatype ~= 'tabular-data'
and propertyClaims[ 1 ].mainsnak.datatype ~= 'wikibase-property'
then
local label = propertyLabel( propertyId );
if propertyClaims[ 1 ].mainsnak.datatype == 'commonsMedia' then
result = result .. getLine( renderValue( frame, propertyId, { alt = label } ), 'image' );
else
result = result .. getValue( label, renderValue( frame, propertyId ) );
end
skipPropertyIds[ propertyId ] = true
shownProperties = shownProperties + 1
end
end
-- Footer.
---- Map.
if claims.P625 ~= nil then
result = result .. getLine( renderValue( frame, 'map' ), 'text' );
end
---- Commons.
if claims.P373 ~= nil then
result = result .. getLine( expandTemplate( frame, getTemplate( 'P373' ), { from = entityId } ), 'below' );
end
result = result .. '</table>';
-- Coords.
if claims.P625 ~= nil then
result = result .. renderValue( frame, 'P625', { display = 'title' } );
end
-- Tracking category.
if config and config.categories and config.categories['few-properties-shown'] then
if shownProperties < 4 then
result = result .. '[[Category:' .. config.categories['few-properties-shown'] .. '|' .. shownProperties .. ']]'
end
end
return result;
end
return p;