Модуль:External links

Из Википедии, бесплатной энциклопедии

Документация

Модуль используется в шаблоне {{Внешние ссылки}}. Список внешних ссылок см. на Модуль:External links/data. Примеры использования для тестов см. в Модуль:External links/песочница.

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 moduleNavbar = require( 'Module:Navbar' )._ruwikiNavbar -- can be changed to a regular one 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 ) .. ':&nbsp;' .. 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 .. '&nbsp;' .. 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 .. '&nbsp;<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 .. ' +&nbsp;' .. ( #qualifiers[ 'P400' ] - 1 ) .. '&nbsp;платформ' 					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 = moduleNavbar({ templatelink }) .. 		'&nbsp;[[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>&nbsp;&nbsp;' .. 			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