Модуль:Universal infocard
Материал из Occultica
Для документации этого модуля может быть создана страница Модуль:Universal infocard/doc
--[[ 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 and config.templates[ propertyId ] then return config.templates[ propertyId ]; 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 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, header ) local result = ''; local tag = header and 'th scope="colgroup"' or 'td'; if ( value and string.len( value ) ~= 0 ) then result = result .. '<tr><' .. tag .. ' colspan="2"'.. getClassString( class ) .. '>'; result = result .. value; result = result .. '</' .. tag .. '></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 scope="row"' .. 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" } } ]]; return args.frame:extensionTag{ name = 'mapframe', content = '[' .. mapContent .. ']', args = { 'frameless', align = 'center', latitude = coord['latitude'], longitude = coord['longitude'], zoom = 11, width = 300, height = 250, } }; end function renderValue( frame, propertyId, args ) local tplArgs = { propertyId, from = entityId, entityId = 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 -- Filter deprecated claims and returning only preferred ones if present. function propertyHasEntity( claims, itemId ) if not claims then return false; 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 return true; end end return false; 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' .. 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' .. 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 = getTemplate( 'title' ); -- TODO: Make it possible to specify a template for any value, not just Q5. if propertyHasEntity( claims.P31, 'Q5' ) then local titleTemplateQ5 = getTemplate( 'title_Q5' ); if titleTemplateQ5 then titleTemplate = titleTemplateQ5; end end 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', true ); ---- 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;