Дополнительные действия
Для документации этого модуля может быть создана страница Модуль: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 templateTitle = 'Ссылки на внешние ресурсы' 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, entityId, separateLabel ) -- Create rows local elements = {} local data = {} for _, params in pairs( configuration ) do local resourceId = params local propertyId = resourceId[ 2 ] local qid if string.match( propertyId, '^P%d+:Q%d+$' ) then local parts = mw.text.split( propertyId, ':', true ) propertyId = parts[ 1 ] qid = parts[ 2 ] end local claims = mw.wikibase.getBestStatements( entityId, propertyId ) 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[ propertyId ] ) 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 entityId = 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 entityId = string.upper( parentArgs[ 'from' ] ) elseif parentArgs[ 'd' ] and parentArgs[ 'd' ] ~= '' then entityId = string.upper( parentArgs[ 'd' ] ) else entityId = mw.wikibase.getEntityIdForCurrentPage() 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 if not entityId then return '' end local navboxData = { name = 'External links', title = templateTitle, titlestyle = 'display:none', state = 'plain', bodyclass = 'hlist', bodystyle = 'padding-top:1px', } 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, entityId, 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:' .. (entityId 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