Модуль:Disambig
На данный момент реализует вывод шаблона {{Неоднозначность}} и часть вывода {{Категория-неоднозначность}}. Со временем будет дописан, чтобы выполнять разного рода проверки на страницах значений. Код вызова модуля: {{#invoke:Disambig|main}} ДанныеВызывает и обрабатывает Module:Disambig/data.json для данных о разных типах значений. Все доступные типы (кроме служебных) можно увидеть на Шаблон:Неоднозначность#Поддерживаемые типы. Данные на странице данных представлены в следующем виде: "ключ": {
"aliases": [
"алиас 1",
"алиас 2",
"алиас_3"
],
"image": "иконка",
"desc": "описание формата «Список статей о X»",
"short": "необязательно: краткое описание того же формата",
"about": "уточнение формата «о конкретном X»",
"seeAlsoCategory": "для персоналий: категория со списком всех статей с названием",
"category": "подкатегория формата «Страницы значений:X»",
"categorySortPrefixes": [
"префиксы в названии через запятую, которые следует поставить в конец при сортировке в категориях"
]
}
По возможности следует добавлять минимальное число алиасов (желательно 0). Минимальный пустой шаблон для вставки нового типа на страницу: "ключ": {
"image": "",
"desc": "",
"about": "",
"category": ""
}
Новые типы должны обсуждаться на Обсуждение проекта:Страницы значений перед добавлением. Функции
require( 'strict' )
local p = {}
local getArgs = require( 'Module:Arguments' ).getArgs
local escapePattern = require( 'Module:String' )._escapePattern
local nestedQuotes
local currentTitle = mw.title.getCurrentTitle()
-- [[Module:Disambig/styles.css]]
local templateStylesPage = 'Module:Disambig/styles.css'
local data = mw.loadJsonData( 'Module:Disambig/data.json' )
local configData = data[ '--config' ]
local defaultData = data[ '--disambig' ]
local errorData = data[ '--error' ]
local function getAliases()
local result = {}
for key, val in pairs( data ) do
if val[ 'aliases' ] then
for i, alias in ipairs( val[ 'aliases' ] ) do
result[ alias ] = key
end
end
end
return result
end
local aliases = getAliases()
local function isEmpty( str )
return str == nil or str == ''
end
local function escapeRepl( text )
-- Replace % to %% to avoid %1, %2, %3 being treated as groups
return ( mw.ustring.gsub( text, '%%', '%%%' ) )
end
local function getConfig( key, isRequired )
if configData == nil then
return error( 'getConfig: config is missing in Module:Disambig/data.json' )
end
if isRequired ~= false and isEmpty( configData[ key ] ) then
return error( string.format( 'getConfig: "%s" key is missing in Module:Disambig/data.json' ) )
end
return configData[ key ] or nil
end
local function isNotOther( dtype )
local aliasesOther = data[ '--other' ][ 'aliases' ]
for i, alias in ipairs( aliasesOther ) do
if dtype == alias then
return false
end
end
return true
end
local function pageNameBase( page )
return ( mw.ustring.gsub( page, '^%s*(.+)%s+%b()%s*$', '%1' ) )
end
local function setCategory( title, key )
if isEmpty( title ) then
return ''
end
if not isEmpty( key ) then
title = title .. '|' .. key
end
return string.format( '[[Category:%s]]', title )
end
local function formatText( str, params, frame )
if isEmpty( str ) then
return ''
end
-- Replace spaces after specified patterns to non-breaking spaces
local nbspPatterns = getConfig( 'nbspPatterns', false )
if type( nbspPatterns ) ~= 'table' then
nbspPatterns = {}
end
for i, val in ipairs( nbspPatterns ) do
-- last symbol is Unicode to allow replacements near itself
str = mw.ustring.gsub( str, '(%s)(' .. val .. ') ', '%1%2 ' )
end
-- Replace provided parameters in form of {param}
if params ~= nil and type( params ) == 'table' then
for key, val in pairs( params ) do
str = mw.ustring.gsub( str, '%{' .. key .. '%}', escapeRepl( val ) )
end
end
-- Preprocess if frame was provided
if frame ~= nil then
return frame:preprocess( str )
end
return str
end
local function formatNestedQuotes( str )
if str:find( '«' ) ~= nil then
nestedQuotes = nestedQuotes or require( 'Модуль:Вложенные кавычки' )._main
return nestedQuotes( str )
end
return str
end
local function getFixMessage( about )
local aboutStr = getConfig( 'aboutDefault' )
if not isEmpty( about ) then
aboutStr = formatText( getConfig( 'about' ), {
about = about,
} )
end
local page = currentTitle.fullText
local wlh = mw.title.new( 'Special:WhatLinksHere/' .. page )
return formatText( getConfig( 'fixLinks' ), {
about = aboutStr,
url = wlh:fullUrl( 'namespace=0&hidetrans=1' ),
} )
end
local function getPseudoBlock( text, class )
local result = mw.html.create( 'div' )
result:addClass( 'ts-disambig-block ' .. ( class or '' ) )
result:tag( 'div' )
:addClass( 'ts-disambig-image' )
result:tag( 'div' )
:addClass( 'ts-disambig-text' )
:wikitext( text )
return result
end
local function getProjectLink( node )
if node == nil then
return error( 'getProjectLink: no node' )
end
local projectPage = getConfig( 'projectPage', false )
local projectIcon = getConfig( 'projectIcon', false )
local projectLabel = getConfig( 'projectLabel', false )
if isEmpty( projectPage ) or isEmpty( projectIcon ) or isEmpty( projectLabel ) then
return
end
local projTitle = mw.title.new( projectPage )
node:tag( 'div' )
:addClass( 'ts-disambig-projectLink plainlinks group-user-show' )
:tag( 'span' )
:wikitext( string.format(
'[[File:%s|20x20px|link=|alt=]][%s %s]',
projectIcon,
projTitle:fullUrl(),
projectLabel
) )
end
local seeAlsoLinks = {}
local function getSeeAlso( category, isSingle )
local page = pageNameBase( currentTitle.fullText )
local seeAlso = formatText( getConfig( 'seeAlso' ) )
-- Get search link with intitle: with titles with words
local intitleLink = '.'
if isSingle and mw.ustring.find( page, '%a' ) ~= nil then
local pageParts = mw.text.split( mw.ustring.gsub( page, '[,«»?!—%%]', '' ), ' ' )
if not isEmpty( pageParts[ 1 ] ) then
local intitle = mw.uri.encode( 'intitle:"' .. table.concat( pageParts, '" intitle:"' ) .. '"' )
local intitleLabel = formatText( getConfig( 'seeAlsoIntitle' ) )
intitleLink = string.format(
', [%s %s].',
mw.title.new( 'Special:Search' ):fullUrl(
string.format( 'search=%s&sort=create_timestamp_desc', intitle )
),
intitleLabel
)
end
end
if not isEmpty( category ) then
if seeAlsoLinks[ category ] == true then
return ''
end
seeAlsoLinks[ category ] = true
local cat = mw.title.new( 'Category:' .. category )
local catLabel = formatText( getConfig( 'seeAlsoCategory' ) )
return string.format(
'%s [%s <span title="%s">%s</span>]',
seeAlso,
cat:fullUrl( 'from=' .. mw.uri.encode( page ) ),
cat.fullText,
catLabel
) .. intitleLink
end
local pageText = formatNestedQuotes( page )
local prefixIndexLabel = formatText( getConfig( 'seeAlsoPrefixIndex' ), {
prefix = pageText,
} )
return string.format(
'%s [[Special:PrefixIndex/%s|%s]]',
seeAlso,
page,
prefixIndexLabel
) .. intitleLink
end
local function getWrapper( node )
return node:tag( 'div' )
:attr( 'id', 'disambig' )
:attr( 'role', 'note' )
:addClass( 'ts-disambig-mbox metadata plainlinks' )
end
-- Renders a single disambiguation type message
function p._renderPart( frame, data, isSingle, dtype )
if frame == nil then
frame = mw.getCurrentFrame()
end
if type( data ) ~= 'table' or isEmpty( data[ 'desc' ] ) or isEmpty( data[ 'image' ] ) then
return p._renderPart( frame, errorData, isSingle, dtype )
end
local node = mw.html.create( '' )
local result = node:tag( isSingle and 'div' or 'li' )
result:addClass( 'ts-disambig-block' )
local imageSize = isSingle and '30x40px' or '20x20px'
result:tag( 'div' )
:addClass( 'ts-disambig-image' )
:wikitext(
string.format( '[[File:%s|%s|class=noresize|link=|alt=]]', data.image, imageSize )
)
local seeAlsoCat = data[ 'seeAlsoCategory' ]
local text = formatText( data[ 'desc' ] )
local textDiv = result:tag( 'div' )
:addClass( 'ts-disambig-text' )
if isSingle then
if text:find( 'class="error"' ) ~= nil then
text = formatText( text, {
type = dtype,
}, frame )
else
local fullStop = text:find( '%.$' ) == nil and '.' or ''
text = string.format( '[[%s|%s%s]]', getConfig( 'helpPage' ), text, fullStop )
end
textDiv:tag( 'div' ):wikitext( text )
if dtype == '--category' then
textDiv:tag( 'div' ):wikitext( formatText( data[ 'about' ] ) )
else
textDiv:tag( 'div' ):wikitext( getFixMessage( data[ 'about' ] ) )
node:node( getPseudoBlock( getSeeAlso( seeAlsoCat, isSingle ) ) )
end
else
if data[ 'short' ] then
text = formatText( data[ 'short' ], nil, frame )
end
if text:find( 'class="error"' ) ~= nil then
text = formatText( text, {
type = dtype,
}, frame )
else
text = formatText( text ) .. '.'
end
if data[ 'short' ] == '' then
text = ''
end
local addendum = not isEmpty( seeAlsoCat ) and getSeeAlso( seeAlsoCat, isSingle ) or ''
textDiv:wikitext( text .. addendum )
end
local defaultNs = data[ 'categoryNs' ] or 0
if currentTitle.namespace == defaultNs then
-- Assign default category here since it won’t be otherwise
if isSingle and currentTitle.namespace == 0 then
textDiv:wikitext( setCategory( defaultData[ 'category' ] ) )
end
-- Assign a default sort key if title matches a prefix in config
local defaultSortPrefixes = data[ 'categorySortPrefixes' ]
if isEmpty( defaultSortPrefixes ) ~= nil and type( defaultSortPrefixes ) == 'table' then
local cleanTitle = mw.ustring.gsub( pageNameBase( currentTitle.text ), '[«»„“"\']', '' )
for i, prefix in ipairs( defaultSortPrefixes ) do
local pMatch = mw.ustring.match( cleanTitle, '^' .. escapePattern( prefix ) .. ' ' )
if pMatch ~= nil then
local sortKey = mw.ustring.gsub( cleanTitle, pMatch, '' )
sortKey = mw.text.trim( sortKey )
if sortKey ~= "" then
textDiv:wikitext( frame:preprocess(
string.format( '{{DEFAULTSORT:%s, %s}}', sortKey, pMatch )
) )
break
end
end
end
end
-- Assign the category
textDiv:wikitext( setCategory( data[ 'category' ] ) )
if not isEmpty( data[ 'add' ] ) then
textDiv:wikitext( formatText( data[ 'add' ], nil, frame ) )
end
end
return node
end
-- Chooses which disambiguation type message to show
function p._getPart( frame, dtype, isSingle )
if isEmpty( dtype ) then
return p._renderPart( frame, errorData, isSingle, '*' ), dtype
end
dtype = mw.ustring.lower( dtype )
if dtype:find( '/' ) then
dtype = mw.text.split( dtype, '/' )[ 1 ]
end
local alias = aliases[ dtype ]
if data[ dtype ] == nil and alias == nil then
return p._renderPart( frame, errorData, isSingle, dtype ), dtype
end
if data[ dtype ] ~= nil then
return p._renderPart( frame, data[ dtype ], isSingle, dtype ), dtype
end
return p._renderPart( frame, data[ alias ], isSingle, dtype ), alias
end
-- Documentation for [[Template:Disambig]]
function p._doc( frame )
if frame == nil then
frame = mw.getCurrentFrame()
end
local result = mw.html.create( 'table' )
:addClass( 'wikitable sortable plainlinks' )
result
:tag( 'caption' )
:wikitext( getConfig( 'docTable' ) )
result:tag( 'tr' )
:tag( 'th' )
:attr( 'scope', 'col' )
:wikitext( getConfig( 'docColumnCode' ) )
:tag( 'th' )
:attr( 'scope', 'col' )
:wikitext( getConfig( 'docColumnOutput' ) )
for dtype, val in pairs( data ) do
local als = val[ 'aliases' ]
if dtype:find( '^%-%-' ) == nil or dtype == '--other' then
local displayedType = dtype
local aliases = ''
if dtype == '--other' then
displayedType = als[ 1 ]
end
if als then
for i, alias in ipairs( als ) do
if dtype ~= '--other' or i ~= 1 then
aliases = string.format( '%s, <code>%s</code>', aliases, alias )
end
end
aliases = aliases:gsub( ', ', '', 1 )
aliases = string.format( '<br><i style="opacity:0.85">%s</i>', aliases )
end
-- Replace <li> to <div> here
local template = tostring( p._getPart( frame, dtype, false ) )
template = mw.ustring.gsub( template, '<(/?)li', '<%1div' )
result:tag( 'tr' )
:tag( 'td' )
:attr( 'style', 'font-size:85%' )
:wikitext( string.format( '<code>%s</code>%s', displayedType, aliases ) )
:tag( 'td' )
:attr( 'style', 'font-style:italic' )
:wikitext( template )
end
end
return tostring( result )
end
function p.doc( frame )
return p._doc( frame )
end
-- Generate suggested values in TemplateData blocks
function p._templateData( frame, content )
if isEmpty( content ) then
return ''
end
if frame == nil then
frame = mw.getCurrentFrame()
end
local typeCount = 1
local suggestedValues = {}
for dtype, val in pairs( data ) do
if dtype:find( '^%-%-' ) == nil or dtype == '--other' then
if dtype == '--other' then
suggestedValues[ typeCount ] = val[ 'aliases' ][ 1 ]
else
suggestedValues[ typeCount ] = dtype
end
typeCount = typeCount + 1
end
end
suggestedValues = table.concat( suggestedValues, '", "' )
content = mw.ustring.gsub(
content,
'"suggestedvalues": %[%]',
string.format( '"suggestedvalues": ["%s"]', suggestedValues )
)
return frame:extensionTag{
name = 'templatedata',
content = content,
}
end
function p.templateData( frame )
local args = getArgs( frame )
local content = args[ 1 ]
return p._templateData( frame, content )
end
-- Checks for errors in page code
local function checkErrors( frame, args )
if currentTitle.namespace ~= 0 then
return ''
end
-- Check if current page is a redirect
if currentTitle.isRedirect then
return setCategory( errorData[ 'category' ], '*' )
end
local content = currentTitle:getContent()
if isEmpty( content ) then
return ''
end
content = mw.text.trim( content )
-- Case-insensitive template name
local template = frame:getParent():getTitle()
local mwTitle = mw.title.new( template )
local templatePattern = string.format(
"[%s%s]%s",
mw.ustring.upper( mw.ustring.sub( mwTitle.text, 1, 1 ) ),
mw.ustring.lower( mw.ustring.sub( mwTitle.text, 1, 1 ) ),
mw.ustring.gsub( escapePattern( mwTitle.text ), '^.', '' )
)
-- Check if it is at the start
if mw.ustring.find( content, '{{' .. templatePattern ) == 1 then
return setCategory( errorData[ 'category' ], '↓' )
end
-- Check if it is not the last template
if mw.ustring.find( content, '{{' .. templatePattern .. '[^%}]-}}.-{{' ) ~= nil then
return setCategory( errorData[ 'category' ], '↓' )
end
for key, val in pairs( args ) do
if type( key ) ~= 'number' then
return setCategory( errorData[ 'category' ], '~' )
end
end
return ''
end
-- Protects templates from substitution by substituting them with their own parameters
function p._substing( frame, args, template )
if args == nil then
args = getArgs( frame, {
parentOnly = true,
} )
end
local mTemplateInvocation = require( 'Module:Template invocation' )
local name = mTemplateInvocation.name( template or frame:getParent():getTitle() )
return mTemplateInvocation.invocation( name, args )
end
-- Renders {{Disambig}} template
function p._main( frame, args )
if frame == nil then
frame = mw.getCurrentFrame()
end
local result = mw.html.create( 'div' )
:addClass( 'ts-disambig' )
local reflist = result:tag( 'div' )
:addClass( 'ts-disambig-reflist' )
reflist:tag( 'div' )
:attr( 'role', 'heading' )
:attr( 'aria-level', 2 )
:wikitext( getConfig( 'reflistLabel' ) )
reflist:wikitext( frame:extensionTag{
name = 'references',
} )
local disambig = getWrapper( result )
if isEmpty( args[ 1 ] ) then
local hasTypes = false
for i, dtype in pairs( args ) do
if tonumber( i ) ~= nil and not isEmpty( dtype ) then
hasTypes = true
break
end
end
if not hasTypes then
disambig:node( p._getPart( frame, '--disambig', true ) )
else
disambig:node( p._renderPart( frame, errorData, true, '()' ) )
end
elseif isEmpty( args[ 2 ] ) then
local dtype = args[ 1 ]
disambig:node( p._getPart( frame, dtype, true ) )
else
disambig:node( p._getPart( frame, '--disambig', true ) )
disambig:node( getPseudoBlock( getConfig( 'typesLabel' ), 'ts-disambig-listIntro' ) )
local list = disambig:tag( 'ul' )
:attr( 'role', 'list' )
:addClass( 'ts-disambig-list' )
local hasOther = false
local usedTypes = {}
for i, dtype in ipairs( args ) do
if isNotOther( dtype ) then
local part, usedType = p._getPart( frame, dtype, false )
if not usedTypes[ usedType ] then
list:node( part )
usedTypes[ usedType ] = true
else
list:node( p._renderPart( frame, errorData, false, dtype ) )
end
else
hasOther = true
end
end
if hasOther then
list:node( p._getPart( frame, '--other', false ) )
end
end
getProjectLink( result )
result = tostring( result )
if currentTitle.namespace == 0 then
result = '__DISAMBIG__' .. frame:extensionTag{
name = 'indicator',
content = string.format( '[[File:Disambig.svg|20px|link=%s|%s]]', getConfig( 'helpPage' ), getConfig( 'helpLabel' ) ),
args = { name = '0-disambig' },
} .. result
end
return frame:extensionTag{
name = 'templatestyles',
args = { src = templateStylesPage },
} .. result
end
function p.main( frame )
if mw.isSubsting() then
return p._substing( frame )
end
local args = getArgs( frame )
return p._main( frame, args ) .. checkErrors( frame, args )
end
-- Renders alias templates with substing capabilities
function p.alias( frame )
local args = getArgs( frame )
local template = args[ '$template' ]
args[ '$template' ] = nil
if mw.isSubsting() then
return p._substing( frame, args, 'Template:' .. template )
end
return frame:expandTemplate{
title = template,
args = { args[ 1 ] },
} .. checkErrors( frame, args )
end
-- Renders {{Category disambiguation}} template
function p._category( frame, args )
if frame == nil then
frame = mw.getCurrentFrame()
end
if isEmpty( args[ 2 ] ) and isEmpty( args[ 4 ] ) then
return error( getConfig( 'categoryError' ) )
end
local params = {}
for key, val in pairs( args ) do
if type( key ) == 'number' then
if isEmpty( params[ key - 1 ] ) then
params[ key - 1 ] = params[ key - 1 ] or ''
end
params[ key ] = val
end
end
local result = mw.html.create( 'div' )
:addClass( 'ts-disambig' )
local disambig = getWrapper( result )
disambig:node( p._getPart( frame, '--category', true ) )
disambig:node( getPseudoBlock( getConfig( 'categoryIntro' ), 'ts-disambig-listIntro' ) )
local list = disambig:tag( 'ul' )
:attr( 'role', 'list' )
:addClass( 'ts-disambig-list ts-disambig-categoryList' )
for i, catName in ipairs( params ) do
if i % 2 == 0 and not isEmpty( catName ) then
local catLabel = formatNestedQuotes( catName )
local text = string.format( '[[:Category:%s|%s]]', catName, catLabel )
local label = args[ i - 1 ]
if not isEmpty( label ) then
text = string.format(
'<i>%s</i> — %s ',
label,
formatText( getConfig( 'categoryInLabel' ), {
category = text,
} )
)
else
text = string.format( '<b>%s</b>', text )
end
list:node( getPseudoBlock( text ) )
end
end
getProjectLink( result )
result = tostring( result )
if currentTitle.namespace == 14 then
result = '__DISAMBIG__' .. '__EXPECTUNUSEDCATEGORY__' .. result
end
return frame:extensionTag{
name = 'templatestyles',
args = { src = templateStylesPage },
} .. result
end
function p.category( frame )
if mw.isSubsting() then
return p._substing( frame )
end
return p._category( frame, getArgs( frame ) )
end
return p
|
Index:
pl ar de en es fr it arz nl ja pt ceb sv uk vi war zh ru af ast az bg zh-min-nan bn be ca cs cy da et el eo eu fa gl ko hi hr id he ka la lv lt hu mk ms min no nn ce uz kk ro simple sk sl sr sh fi ta tt th tg azb tr ur zh-yue hy my ace als am an hyw ban bjn map-bms ba be-tarask bcl bpy bar bs br cv nv eml hif fo fy ga gd gu hak ha hsb io ig ilo ia ie os is jv kn ht ku ckb ky mrj lb lij li lmo mai mg ml zh-classical mr xmf mzn cdo mn nap new ne frr oc mhr or as pa pnb ps pms nds crh qu sa sah sco sq scn si sd szl su sw tl shn te bug vec vo wa wuu yi yo diq bat-smg zu lad kbd ang smn ab roa-rup frp arc gn av ay bh bi bo bxr cbk-zam co za dag ary se pdc dv dsb myv ext fur gv gag inh ki glk gan guw xal haw rw kbp pam csb kw km kv koi kg gom ks gcr lo lbe ltg lez nia ln jbo lg mt mi tw mwl mdf mnw nqo fj nah na nds-nl nrm nov om pi pag pap pfl pcd krc kaa ksh rm rue sm sat sc trv stq nso sn cu so srn kab roa-tara tet tpi to chr tum tk tyv udm ug vep fiu-vro vls wo xh zea ty ak bm ch ny ee ff got iu ik kl mad cr pih ami pwn pnt dz rmy rn sg st tn ss ti din chy ts kcg ve
Portal di Ensiklopedia Dunia