Модуль:Disambig
Перейти к навигации
Перейти к поиску
Внимание! Это один из самых используемых модулей. |
Этот модуль использует TemplateStyles и загружает следующие таблицы CSS-стилей:
|
На данный момент реализует вывод шаблона {{Неоднозначность}}. Со временем будет дописан, чтобы выполнять разного рода проверки на страницах значений.
Код вызова модуля:
{{#invoke:Disambig|main}}
Функции:
p._main
— для вызова из другого Луа-кода.p.main
— для вызова из шаблонов.p.doc
/p._doc
— генерация автоматической таблицы документации с известными типами значений.p.templateData
/p._templateData
— добавление известных типов значений в блок TemplateData на странице документации.
Данные
Вызывает и обрабатывает Module:Disambig/data.json для данных о разных типах значений. Все доступные типы (кроме служебных) можно увидеть на Шаблон:Неоднозначность#Поддерживаемые типы. Данные на странице данных представлены в следующем виде:
"ключ": {
"aliases": [
"алиас 1",
"алиас 2",
"алиас_3"
],
"image": "иконка",
"desc": "описание формата «Список статей о X»",
"short": "необязательно: краткое описание того же формата",
"about": "уточнение формата «о конкретном X»",
"seeAlsoCategory": "для персоналий: категория со списком всех статей с названием",
"category": "подкатегория формата «Страницы значений:X»"
}
По возможности следует добавлять минимальное число алиасов (желательно 0).
Минимальный пустой шаблон для вставки нового типа на страницу:
"ключ": {
"image": "",
"desc": "",
"about": "",
"category": ""
}
Новые типы должны обсуждаться на Обсуждение проекта:Страницы значений перед добавлением.
require( 'strict' )
local p = {}
local getArgs = require( 'Module:Arguments' ).getArgs
-- [[Module:Disambig/styles.css]]
local templateStylesPage = 'Module:Disambig/styles.css'
local data = mw.loadJsonData( 'Module:Disambig/data.json' )
local defaultData = data[ '--disambig' ]
local currentTitle = mw.title.getCurrentTitle()
-- Uses ABOUT_STR/ABOUT_DEFAULT at the end
local DISAMBIG_HELP = 'Википедия:Неоднозначность'
local DISAMBIG_HELP_LABEL = 'Справка о страницах значений'
local DISAMBIG_REFLIST = 'Примечания'
local DISAMBIG_TYPES = 'На этой странице приведены:'
local FIX_LINKS = 'Если вы попали сюда из [%s <span title="Ссылки на эту страницу из других статей">другой статьи Википедии</span>], пожалуйста, вернитесь и [[Википедия:Толкование ссылок|уточните ссылку]] так, чтобы она указывала на %s.'
local SEE_ALSO_LINK = ' См. также [[Special:PrefixIndex/%s|список страниц с «%s» в начале названия]].'
local SEE_ALSO_CAT = ' См. также [%s <span title="%s">полный список существующих статей</span>].'
local ABOUT_STR = 'статью %s'
local ABOUT_DEFAULT = 'нужную статью'
local DISAMBIG_DOC = 'Текущие типы значений'
local DISAMBIG_DOC_CODE = 'Код'
local DISAMBIG_DOC_VIEW = 'Отображение'
-- Lua patterns for words where the module needs to insert (see formatText method)
local NBSP_PATTERNS = { 'во?', 'для', 'же', 'и', 'из', 'или', 'на', 'об?', 'со?', '[Сс]м%.', 'чтобы' }
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 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, frame )
if isEmpty( str ) then
return ''
end
for i, val in ipairs( NBSP_PATTERNS ) do
-- last symbol is Unicode to allow replacements near itself
str = mw.ustring.gsub( str, '(%s)(' .. val .. ') ', '%1%2 ' )
end
if frame ~= nil then
return frame:preprocess( str )
end
return str
end
local function getFixMessage( about )
if isEmpty( about ) then
about = ABOUT_DEFAULT
else
about = string.format( ABOUT_STR, about )
end
local page = currentTitle.fullText
local wlh = mw.title.new( 'Special:WhatLinksHere/' .. page )
return string.format(
formatText( FIX_LINKS ),
wlh:fullUrl( 'namespace=0' ),
about
)
end
local function getSeeAlsoLink( category )
local page = pageNameBase( currentTitle.fullText )
if not isEmpty( category ) then
local cat = mw.title.new( 'Category:' .. category )
return string.format(
formatText( SEE_ALSO_CAT ),
cat:fullUrl( 'from=' .. page ),
cat.fullText
)
end
return string.format(
formatText( SEE_ALSO_LINK ),
page,
page
)
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, data[ '--error' ], isSingle, dtype )
end
local result = mw.html.create( 'li' )
if isSingle then
result = mw.html.create( 'div' )
end
result:addClass( 'ts-disambig-block' )
local imageSize = isSingle and '30px' or '20px'
result:tag( 'div' )
:addClass( 'ts-disambig-image noprint' )
:wikitext(
string.format( '[[File:%s|%s|class=noresize|link=|alt=]]', data.image, imageSize )
)
local text = formatText( data[ 'desc' ] )
local addendum = ''
local textDiv = result:tag( 'div' )
:addClass( 'ts-disambig-text' )
if isSingle then
if text:find( 'class="error"' ) then
text = formatText( string.format( text, dtype ), frame )
else
text = string.format( '[[%s|%s]].', DISAMBIG_HELP, text )
end
textDiv:tag( 'div' ):wikitext( text )
if isSingle and dtype ~= '--disambig' then
addendum = getSeeAlsoLink( data[ 'seeAlsoCategory' ] )
end
textDiv:tag( 'div' )
:wikitext( getFixMessage( data[ 'about' ] ) .. addendum )
else
if data[ 'short' ] then
text = formatText( data[ 'short' ], frame )
end
if text:find( 'class="error"' ) then
text = formatText( string.format( text, dtype ), frame )
else
text = formatText( text ) .. '.'
end
if data[ 'short' ] == '' then
text = ''
end
if dtype == '--all' or dtype == '--other' or not isEmpty( data[ 'seeAlsoCategory' ] ) then
addendum = getSeeAlsoLink( data[ 'seeAlsoCategory' ] )
end
textDiv:wikitext( text .. addendum )
end
if currentTitle.namespace == 0 then
-- Assign default category here since it won’t be otherwise
if isSingle and currentTitle.namespace == 0 then
textDiv:wikitext( setCategory( defaultData[ 'category' ] ) )
end
textDiv:wikitext( setCategory( data[ 'category' ], data[ 'categoryKey' ] ) )
if not isEmpty( data[ 'add' ] ) then
textDiv:wikitext( formatText( data[ 'add' ], frame ) )
end
end
return result
end
-- Chooses which disambiguation type message to show
function p._getPart( frame, dtype, isSingle )
if isEmpty( dtype ) then
return p._renderPart( frame, data[ '--error' ], isSingle, '*' )
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, data[ '--error' ], isSingle, dtype )
end
if data[ dtype ] ~= nil then
return p._renderPart( frame, data[ dtype ], isSingle, dtype )
end
return p._renderPart( frame, data[ alias ], isSingle, dtype )
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( DISAMBIG_DOC )
result:tag( 'tr' )
:tag( 'th' )
:attr( 'scope', 'col' )
:wikitext( DISAMBIG_DOC_CODE )
:tag( 'th' )
:attr( 'scope', 'col' )
:wikitext( DISAMBIG_DOC_VIEW )
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
function p._checkErrors( frame )
if currentTitle.namespace ~= 0 then
return ''
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( mwTitle.text, '^.', '' )
)
-- Only works on pages with direct transclusions
if mw.ustring.find( content, templatePattern ) == 3 then
return setCategory( data[ '--error' ][ 'category' ], '↓' )
end
return ''
end
-- Protects templates from substitution by substituting them with their own parameters
function p._substing( frame )
local args = getArgs( frame, {
parentOnly = true,
} )
local mTemplateInvocation = require( 'Module:Template invocation' )
local name = mTemplateInvocation.name( 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( DISAMBIG_REFLIST )
reflist:wikitext( frame:extensionTag{
name = 'references',
} )
local disambig = result:tag( 'div' )
:attr( 'id', 'disambig' )
:attr( 'role', 'note' )
:addClass( 'ts-disambig-mbox metadata plainlinks' )
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-single', true ) )
else
disambig:node( p._renderPart( frame, data[ '--error' ], 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:tag( 'div' )
:addClass( 'ts-disambig-beforeList' )
:wikitext( DISAMBIG_TYPES )
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
if not usedTypes[ dtype ] then
list:node( p._getPart( frame, dtype, false ) )
usedTypes[ dtype ] = true
else
list:node( p._renderPart( frame, data[ '--error' ], false, dtype ) )
end
else
hasOther = true
end
end
if hasOther then
list:node( p._getPart( frame, '--other', false ) )
else
list:node( p._getPart( frame, '--all', false ) )
end
end
result = tostring( result )
if currentTitle.namespace == 0 then
result = '__DISAMBIG__' .. frame:extensionTag{
name = 'indicator',
content = string.format( '[[File:Disambig.svg|20px|link=%s|%s]]', DISAMBIG_HELP, DISAMBIG_HELP_LABEL ),
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
return p._checkErrors( frame ) .. p._main( frame, getArgs( frame ) )
end
return p