Модуль:External links
Для документации этого модуля может быть создана страница Модуль:External links/doc
local data = require( 'Module:External links/data' )
-- Localizable part
-- Please note that labels for websites and catalogs are taken from Wikidata (i.e. Wikidata label)
-- Feel free to correct labels and categories here
local categoryTemplateEmpty = 'Википедия:Шаблон «Внешние ссылки» пуст'
local categoryCustomColor = 'Википедия:Шаблон «Внешние ссылки» с нестандартным цветом'
local templateLink = 'Внешние ссылки'
local wikidataLink = 'Перейти к элементу Викиданных'
local refLabels = {
Q1406 = 'Windows',
Q10677 = 'PS1',
Q10680 = 'PS2',
Q10683 = 'PS3',
Q16338 = 'ПК',
Q135321 = 'FDS',
Q170323 = 'DS',
Q170325 = 'PSP',
Q172742 = 'NES',
Q182172 = 'GameCube',
Q183259 = 'SNES',
Q184839 = 'N64',
Q188642 = 'GBA',
Q188808 = 'PS Vita',
Q203597 = '3DS',
Q5014725 = 'PS4',
Q19610114 = 'Switch',
Q63184502 = 'PS5',
}
-- The language codes that should always be displayed even if they have normal rank and a claim with another language and preferred rank exists
local preferredLanguage = 'Q7737' -- russian
local templateColorName = 'цвет'
-- Some projects have "named" colors, defined by templates
local function colorByTitle( frame, colorTitle )
local templateName = 'Цвет/' .. colorTitle
local templateTitle = mw.title.makeTitle( 'Template', templateName )
if not templateTitle or not templateTitle.exists then
return false
end
return frame:expandTemplate{ title = templateName }
end
-- Non-localizable part (not need to localize )
local moduleNavbox = require( 'Module:Navbox' )
local moduleLanguages -- accessed if necessary
local propertyQualifiers = {
P553 = {
P554 = 'url',
},
P1343 = {
P805 = 'iw',
P248 = 'iw', -- deprecated, fallback for P805
P953 = 'url',
P854 = 'url', -- deprecated, fallback for P953
},
}
local p = {}
-- Helper functions
local function replace( str, pattern, repl )
pattern = mw.ustring.gsub( pattern, "[%(%)%.%+%-%*%?%[%]%^%$%%]", "%%%1" ) -- escape pattern
repl = mw.ustring.gsub( repl, "[%%]", "%%%%" ) -- escape replacement
repl = mw.ustring.gsub( repl, " ", "%%%%20" ) -- escape replacement
return mw.ustring.gsub( str, pattern, repl )
end
-- Render functions
local function renderList( elements )
if #elements == 0 then
return ''
end
return '*' .. table.concat( elements , '\n*' ) .. '\n'
end
local function renderLabel( params )
if type( params ) == 'string' then
return params
end
local qid = params[ 1 ]
local default = params[ 2 ]
if #params >= 3 then
local label = params[ 3 ]
local link = mw.wikibase.sitelink( qid )
if link then
return '[[' .. link .. '|' .. label .. ']]'
end
local title = mw.wikibase.label( qid ) or default
if title ~= label then
return '<span title="' .. title .. '" style="border-bottom: 1px dotted; cursor: help;">' .. label .. '</span>'
end
end
return mw.wikibase.label( qid ) or default
end
local function renderLink( resourceData, label, formatter, idAsLabel )
if resourceData.itemId == nil then
return '<span class="error">' .. label .. ': Не удаётся определить элемент</span>[[Категория:Статьи с ошибкой в шаблоне Внешние ссылки]]'
end
local link
if not formatter then
link = resourceData.itemId
idAsLabel = false
elseif type( formatter ) == 'string' then
link = replace( formatter, '$1', resourceData.itemId )
elseif type ( formatter ) == 'function' then
link = formatter( resourceData.itemId, resourceData.qualifiers )
end
-- "Label: ID" without link
if not link or link == '' then
return renderLabel( label ) .. ': ' .. resourceData.itemId
end
local resourceLabel = resourceData.itemId
if not idAsLabel then
resourceLabel = renderLabel( label )
end
local linkFirstChar = mw.ustring.sub( link, 1, 1 )
if linkFirstChar == ':' then
return '[[' .. link .. '|' .. resourceLabel .. ']]'
end
return '[' .. link .. ' ' .. resourceLabel .. ']'
end
local function renderLangRef( languages )
local result = ''
if languages and #languages > 0 then
if moduleLanguages ~= false then -- not false, but maybe nil
if mw.title.makeTitle( 'Module', 'Languages' ).exists
and mw.title.makeTitle( 'Module', 'Languages/data' ).exists
and mw.title.makeTitle( 'Module', 'Wikidata/Language-codes' ).exists then
moduleLanguages = require( 'Module:Languages' )
else
moduleLanguages = false
end
end
if moduleLanguages then
for langIndex, language in pairs( languages ) do
result = result .. ' ' .. moduleLanguages.getWikidataRefHtml( language )
end
end
end
return result
end
local function renderRefs( refs )
local result = ''
if refs and #refs > 0 then
for _, ref in ipairs( refs ) do
result = result .. ' <span class="ref-info">(' .. ref .. ')</span>'
end
end
return result
end
local function renderLinkWithRef( resourceData, label, formatter, idAsLabel )
local link = renderLink( resourceData, label, formatter, idAsLabel )
if link ~= '' then
link = link .. renderLangRef( resourceData.languages )
link = link .. renderRefs( resourceData.refs )
end
return link
end
-- Data fetching functions
local function getValueFromSnak( snak )
if not snak.datavalue then
return
end
if snak.datavalue.type == 'wikibase-entityid' then
return snak.datavalue.value.id
end
if snak.datavalue.type == 'monolingualtext' then
return snak.datavalue.value.text
end
return snak.datavalue.value
end
local function getQualifierSingleValue( statement, qualifierName )
if not statement or not statement.qualifiers or not statement.qualifiers[ qualifierName ] then
return nil
end
for qualifierIndex, qualifier in pairs( statement.qualifiers[ qualifierName ] ) do
if qualifier.datavalue and qualifier.datavalue.type and qualifier.datavalue.value then
return getValueFromSnak( qualifier )
end
end
return nil
end
local function getQualifierValues( statement )
if not statement or not statement.qualifiers then
return {}
end
local result = {}
for qualifierName, qualifiers in pairs( statement.qualifiers ) do
for _, qualifier in pairs( qualifiers ) do
if qualifier.datavalue and qualifier.datavalue.type and qualifier.datavalue.value then
if not result[ qualifierName ] then
result[ qualifierName ] = {}
end
table.insert( result[ qualifierName ], getValueFromSnak( qualifier ) )
end
end
end
return result
end
local function contains( tableStructure, value )
if not tableStructure or not value then
return true
end
for index, line in pairs( tableStructure ) do
if line == value then
return true
end
end
return false
end
local function filterByRank( resourceDatas )
-- itemId, languages. rank = rank
local hasPreffered = false
for index, resourceData in pairs( resourceDatas ) do
if resourceData.rank == 'preferred' then
hasPreffered = true
end
end
if not hasPreffered then
return resourceDatas
end
local result = {}
for index, resourceData in pairs( resourceDatas ) do
if resourceData.rank == 'preferred' or contains( resourceData.languages, preferredLanguage ) then
table.insert( result, resourceData )
end
end
return result
end
local function getLinkData( statement, qualifier, project )
local rank = statement.rank or 'normal'
if rank == 'deprecated' or not statement.mainsnak.datavalue then
return nil
end
local itemId
if qualifier then
itemId = getQualifierSingleValue( statement, qualifier )
else
itemId = statement.mainsnak.datavalue.value
end
if itemId and project then
itemId = mw.wikibase.getSitelink( itemId, project )
end
if not itemId then
return nil
end
local qualifiers = getQualifierValues( statement )
local languages = qualifiers[ 'P407' ]
if not languages then
languages = {}
end
local refs = {}
if qualifiers[ 'P400' ] then
for _, refQid in ipairs( qualifiers[ 'P400' ] ) do
local refLabel = refLabels
if refLabels[ refQid ] then
refLabel = refLabels[ refQid ]
else
refLabel = mw.wikibase.label( refQid ) or refQid
end
if refLabel ~= refQid then
if #qualifiers[ 'P400' ] > 3 then
refLabel = refLabel .. ' + ' .. ( #qualifiers[ 'P400' ] - 1 ) .. ' платформ'
table.insert( refs, refLabel )
break
end
table.insert( refs, refLabel )
end
end
end
return {
itemId = itemId,
qualifiers = qualifiers,
languages = languages,
refs = refs,
rank = rank,
}
end
local function collectLinks( configuration, elementId, separateLabel )
-- Create rows
local elements = {}
local data = {}
local item = mw.wikibase.getEntity( elementId )
if item == nil or item.claims == nil then
return elements
end
for _, params in pairs( configuration ) do
local resourceId = params
local pid = resourceId[ 2 ]
local qid
if string.match( pid, '^P%d+:Q%d+$' ) then
local parts = mw.text.split( pid, ':', true )
pid = parts[ 1 ]
qid = parts[ 2 ]
end
local claims = item.claims[ pid ] or {}
for _, statement in pairs( claims ) do
local linkData
if not qid then
linkData = getLinkData( statement )
elseif getValueFromSnak( statement.mainsnak ) == qid then
for qualifierId, qualifierType in pairs( propertyQualifiers[ pid ] ) do
local project = nil
if qualifierType == 'iw' then
project = params.project
end
linkData = getLinkData( statement, qualifierId, project )
if linkData then
break
end
end
end
if linkData then
if not data[ resourceId ] then
data[ resourceId ] = {}
end
table.insert( data[ resourceId ], linkData )
end
end
end
for resourceId, resourceDatas in pairs( data ) do
data[ resourceId ] = filterByRank( resourceDatas )
end
for _, params in pairs( configuration ) do
local resourceId = params
local resourceDatas = data[ resourceId ]
if resourceDatas ~= nil then
local links = {}
for _, resourceData in pairs( resourceDatas ) do
if separateLabel then
-- Label: ID1, ID2
table.insert( links, renderLinkWithRef( resourceData, '', params[ 3 ], true ) )
else
-- Label · Label
local label = params[ 1 ]
table.insert( elements, renderLinkWithRef( resourceData, label, params[ 3 ] ) )
end
end
if separateLabel and #links then
local result = renderLabel( params[ 1 ] ) .. ': ' .. table.concat( links, ', ' )
table.insert( elements, result )
end
end
end
return elements
end
function p.render( frame )
local colorArg = ''
local byTemplate
local elementId = nil
if frame ~= nil then
local parentArgs = frame:getParent().args
colorArg = parentArgs[ templateColorName ] or parentArgs[ 'color' ] or parentArgs[ 1 ] or ''
if parentArgs[ 'from' ] and parentArgs[ 'from' ] ~= '' then
elementId = string.upper( parentArgs[ 'from' ] )
elseif parentArgs[ 'd' ] and parentArgs[ 'd' ] ~= '' then
elementId = string.upper( parentArgs[ 'd' ] )
end
if colorArg ~= '' then
local firstChar = mw.ustring.sub( colorArg, 1, 1 )
if firstChar ~= '#' then
byTemplate = colorByTitle( frame, colorArg )
if byTemplate then
colorArg = byTemplate
end
end
end
end
local navboxData = {
name = 'External links',
navboxclass = 'navbox ruwikiArticleExternalLinksTable',
bodyclass = 'hlist',
}
if colorArg and colorArg ~= '' then
navboxData.groupstyle = 'background: ' .. colorArg .. ';'
end
local rowIndex = 1
for _, groupData in pairs( data ) do
local isAuthorityControl = groupData.isAuthorityControl
local groupLabel = groupData.label
local groupList = groupData.list
local groupElements = collectLinks( groupList, elementId, isAuthorityControl )
if #groupElements > 0 then
navboxData[ 'group' .. rowIndex ] = groupLabel
navboxData[ 'list' .. rowIndex ] = renderList( groupElements )
if isAuthorityControl then
if #groupElements > 5 then
navboxData[ 'group' .. rowIndex ] = nil
local templateStyles = frame:extensionTag{
name = 'templatestyles',
args = { src = 'Шаблон:Навигационная таблица/styles.css' }
}
local collapsibleNavbox = moduleNavbox._navbox( {
title = groupLabel,
list1 = navboxData['list' .. rowIndex],
border = 'subgroup',
navbar = 'plain',
state = 'collapsed',
titleclass = 'ts-navbox-plaintitle',
bodyclass = 'authoritycontrol',
titlestyle = navboxData.groupstyle,
bodystyle = 'text-align: left;',
} )
navboxData[ 'list' .. rowIndex ] = templateStyles .. collapsibleNavbox
end
end
rowIndex = rowIndex + 1
end
end
if rowIndex == 1 then
if mw.title.getCurrentTitle().namespace == 0 then
return '[[Category:' .. categoryTemplateEmpty .. ']]'
end
return ''
end
local buttons = frame:expandTemplate{ title = 'tnavbar-view', args = { templateLink } } ..
' [[File:OOjs UI icon edit-ltr-progressive.svg|14px|' .. wikidataLink .. '|link=d:'
.. (elementId or mw.wikibase.getEntityIdForCurrentPage()) .. '#identifiers]]'
if navboxData[ 'group1' ] then
navboxData[ 'group1' ] = '<div style="padding: 0 35px 0 0; width: 100%;">' ..
'<div style="float: left;">' .. buttons .. '</div> ' ..
navboxData[ 'group1' ] .. '</div>'
else
navboxData[ 'group1' ] = '<div style="padding: 0; width: 100%;">' .. buttons .. '</div>'
end
local out = moduleNavbox._navbox( navboxData )
if colorArg and colorArg ~= '' and not byTemplate then
out = out .. '[[Category:' .. categoryCustomColor .. ']]'
end
return out
end
return p