Чемпион Южной Америки 1916 Чемпион Южной Америки 1917 Чемпион Южной Америки 1920 Чемпион Южной Америки 1923 Олимпийский чемпион и чемпион мира среди любителей 1924 Чемпион Южной Америки 1924 Чемпион Южной Америки 1926 Олимпийский чемпион и чемпион мира среди любителей 1928 Чемпион мира 1930 Чемпион Южной Америки 1935 Чемпион Южной Америки 1942 Чемпион мира 1950 Чемпион Южной Америки 1956 Чемпион Южной Америки 1959 (Эквадор) Чемпион Южной Америки 1967 Победитель Мундиалито 1980-81 Победитель Кубка Америки 1983 Победитель Кубка Америки 1987 Победитель Кубка Америки 1995 Победитель Кубка Америки 2011

MediaWiki:Common.js — различия между версиями

Материал из CelestePedia
Перейти к: навигация, поиск
Строка 1: Строка 1:
//import scripts
+
/**
importScript('MediaWiki:Editpage.js');
+
* Код MediaWiki:Common.js безусловно загружается всем пользователям на всех страницах. Во избежание
importScript('MediaWiki:Collapsebuttons.js');
+
* отправки лишних запросов по возможности не используйте здесь mw.loader.using с модулями, которые
importScript('User:X-romix/SciRefs.js');
+
* не загружаются по умолчанию (см.
importScript('MediaWiki:Refstandard.js');
+
* [[Обсуждение MediaWiki:Common.js#Список модулей, загружаемых по умолчанию]]). В таком случае
 +
* лучше создать скрытый гаджет, загружаемый по умолчанию, и добавить ему нужные модули в качестве
 +
* зависимостей.
 +
*/
  
addLoadEvent = addOnloadHook
+
/**
importScript_ = importScript
+
* Локальная функция загрузки скриптов с поддержкой указания проекта
 +
*/
 +
var importScript_ = importScript;
 +
importScript = function ( page, proj ) {
 +
if ( !proj ) {
 +
importScript_( page );
 +
} else {
 +
if ( proj.indexOf( '.' ) === -1 ) {
 +
proj += 'celeste-rus.ru';
 +
}
 +
mw.loader.using( 'mediawiki.util' ).done( function () {
 +
mw.loader.load( '//' + proj + '/index.php?title=' + mw.util.wikiUrlencode( page ) +
 +
'&action=raw&ctype=text/javascript' );
 +
} );
 +
}
 +
};
  
 +
/**
 +
* Часто те или иные манипуляции со страницей нужно выполнить как можно раньше, но нет гарантии, что
 +
* к моменту выполнения кода нужный участок DOM готов, а событие полной загрузки страницы происходит
 +
* слишком поздно. В этой функции проверяется наличие элемента $testElement и в случае успеха
 +
* функция-колбэк выполняется, иначе же её выполнение поручается другой функции. Если элемент
 +
* в $testElement имеет содержимое, правильнее указать следующий за ним элемент, чтобы быть
 +
* уверенным, что он загрузился до конца. Имейте в виду, что разные скины часто используют разные
 +
* названия классов и идентификаторов.
 +
*/
 +
function runAsEarlyAsPossible( callback, $testElement, func ) {
 +
func = func || $;
 +
$testElement = $testElement || $( '#footer' );
  
// for backwards compatibility
+
if ( $testElement.length ) {
var addLoadEvent = addOnloadHook;
+
callback();
var import_script = importScript;
+
} else {
var import_style = importStylesheet;
+
func( callback );
var importScript_ = importScript;
+
}
var zeroSectionTip = 'Править'
+
}
  
//  
+
/**
 +
* Настройка обработки «е» и «ё» при сортировке в таблицах
 +
*/
 +
mw.config.set( 'tableSorterCollation', { 'Ё': 'Е', 'ё': 'е' } );
  
  function addLoadEvent(func)
+
/**
  {
+
  * Строки. Иноязычный интерфейс предположительно включают весьма редко, поэтому раздувать этот
  if (window.addEventListener)
+
  * список не стоит. При необходимости добавить много сообщений во много языков можно использовать
  window.addEventListener("load", func, false);
+
  * механизм системных сообщений (= страниц в пространстве MediaWiki, у которых могут быть суффиксы
else if (window.attachEvent)
+
* типа /en). См., как их получение реализовано в MediaWiki:Gadget-sidebarRelated.js.
  window.attachEvent("onload", func);
+
*/
 +
var expandCaption, collapseCaption, zeroSectionTip;
 +
if ( mw.config.get( 'wgUserLanguage' ) === 'en' ) {
 +
expandCaption = 'show';
 +
collapseCaption = 'hide';
 +
zeroSectionTip = 'Edit lead section';
 +
} else {
 +
expandCaption = 'показать';
 +
collapseCaption = 'скрыть';
 +
zeroSectionTip = 'Править преамбулу';
 
}
 
}
  
//Edit zero section
+
/**
function editZeroSection(){
+
  * Сворачиваемые блоки
  if( !wgArticleId ) return
+
  */
  mw.util.$content.find('h2')
+
// Число раскрытых по умолчанию навигационных (и не только) шаблонов, если им задан параметр
.children('.mw-editsection:first')
+
// autocollapse. Участники могут переопределять это значение в личных JS.
.clone().prependTo('#bodyContent')
+
var NavigationBarShowDefault;
.css('float','right')
+
if ( typeof NavigationBarShowDefault === 'undefined' ) {
.find('a')
+
NavigationBarShowDefault = 1;
.attr('title', zeroSectionTip)
 
.attr('href', wgScript + '?title='+mw.util.wikiUrlencode(wgPageName) + '&action=edit&section=0' )
 
}
 
 
 
// hasClass()
 
var hasClass = (function () {
 
    var reCache = {};
 
    return function (element, className) {
 
      return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className);
 
    };
 
})();
 
 
 
 
function sysopProtectPage(){
 
var inp = document.getElementById('mwProtect-level-edit')
 
if (inp) addHandler(inp, 'change', noMoveAutoconfirmedProtection)
 
function noMoveAutoconfirmedProtection(){
 
  var inp = document.getElementById('mwProtectUnchained')
 
  if (!inp || inp.checked) return
 
  inp = document.getElementById('mwProtect-level-move')
 
  if (inp && inp.selectedIndex==1) inp.selectedIndex = 0
 
  inp = document.getElementById('mwProtect-level-delete')
 
  if (inp && inp.selectedIndex==1) inp.selectedIndex = 0
 
}
 
 
}
 
}
  
addOnloadHook(sysopProtectPage);
+
// table.collapsible
 +
// collapsibleTablesItrIdx - временное решние, чтобы не дублировались id,
 +
// если во время срабатывания хука 'wikipage.content' добавляются новые сворачиваемые блоки
 +
var collapsibleTablesItrIdx = 0;
 +
 +
function collapsibleTables( $content ) {
 +
var $btn,
 +
$a,
 +
tblIdx = collapsibleTablesItrIdx,
 +
navboxCount = 0,
 +
notNavboxCount = 0,
 +
colTables = [],
 +
$Tables = $content.find( 'table' );
  
function newSectionLink(){
+
$Tables.each( function ( i, table ) {
var plus = document.getElementById('ca-addsection')
+
if ( $( table ).hasClass( 'collapsible' ) ) {
if (!plus) return
+
var $table = $( this ),
var custom = document.getElementById('add-custom-section')
+
$row = $table.find( 'tr' ).first(),
if (!custom) return
+
$cell = $row.find( 'th' ).first();
plus.firstChild.setAttribute('href', custom.getElementsByTagName('a')[0].href)
+
if ( !$cell.length ) {
 +
return;
 +
}
 +
$table.attr( 'id', 'collapsibleTable' + tblIdx );
 +
$btn = $( '<span>' ).addClass( 'collapseButton' );
 +
$a = $( '<a>' )
 +
.attr( 'id', 'collapseButton' + tblIdx )
 +
.attr( 'href', 'javascript:collapseTable(' + tblIdx + ');' )
 +
// Изменяем цвет ссылки, только если цвет текста в навбоксе нестандартный
 +
.css( 'color', $cell.css( 'color' ) === $( '.mw-body' ).css( 'color' ) ? 'auto' :
 +
$cell.css( 'color' ) )
 +
.text( collapseCaption );
 +
$btn
 +
.append( '[' )
 +
.append( $a )
 +
.append( ']' );
 +
if ( $cell.contents().length ) {
 +
$btn.insertBefore( $cell.contents().first() );
 +
} else {
 +
$btn.appendTo( $cell );
 +
}
 +
// hasClass( 'navbox' ) — временное решение для навшаблонов, ещё не переведённых
 +
// на {{Навигационная таблица}} (также ниже)
 +
if ( $table.hasClass( 'navbox-inner' ) || $table.hasClass( 'navbox' ) ) {
 +
navboxCount++;
 +
} else {
 +
notNavboxCount++;
 +
}
 +
colTables[tblIdx++] = $table;
 +
}
 +
} );
 +
for ( var i = collapsibleTablesItrIdx; i < tblIdx; i++ ) {
 +
if ( colTables[i].hasClass( 'collapsed' ) ||
 +
( colTables[i].hasClass( 'autocollapse' ) &&
 +
( ( ( colTables[i].hasClass( 'navbox-inner' ) || colTables[i].hasClass( 'navbox' ) ) &&
 +
navboxCount > NavigationBarShowDefault ) ||
 +
( !( colTables[i].hasClass( 'navbox-inner' ) || colTables[i].hasClass( 'navbox' ) ) &&
 +
notNavboxCount > NavigationBarShowDefault ) ) ) )
 +
{
 +
collapseTable( i );
 +
}
 +
}
 +
collapsibleTablesItrIdx = tblIdx;
 +
// Нужно переписать код на "mw-collapsible", и заменить использование хука на "wikipage.collapsibleContent"
 +
mw.hook( 'common.collapsibleContent' ).fire( colTables );
 
}
 
}
  
/*WikiEditor/Викификатор*/
+
mw.hook( 'wikipage.content' ).add( collapsibleTables );
if ( $.inArray( mw.config.get( 'wgAction' ), ['edit', 'submit'] ) !== -1 ) {
 
        mw.loader.load( '//ru.wikipedia.org/w/index.php?title=MediaWiki:Gadget-wikificator.js&action=raw&ctype=text/javascript' );
 
}
 
  
var customizeToolbar = function() {
+
function collapseTable( idx ) {
 +
var $table = $( '#collapsibleTable' + idx ),
 +
$rows = $table.children().children( 'tr' ),
 +
$btn = $( '#collapseButton' + idx );
 +
if ( !$table.length || !$rows.length || !$btn.length ) {
 +
return false;
 +
}
  
$( '#wpTextbox1' ).wikiEditor( 'addToToolbar', {
+
var isExpanded = ( $btn.text() === collapseCaption ),
        'section': 'advanced',
+
cssDisplay = isExpanded ? 'none' : $rows.first().css( 'display' );
        'group': 'format',
 
        'tools': {
 
                'wikify': {
 
                        label: 'Викификатор',
 
                        type: 'button',
 
                        icon: '//upload.wikimedia.org/wikipedia/commons/0/06/Wikify-toolbutton.png',
 
                            action: {
 
                                  type: 'callback',
 
                                      execute: function(context){
 
                                              Wikify();
 
                                      }
 
                            }
 
                }
 
        }
 
} );
 
};
 
 
if ( $.inArray( mw.config.get( 'wgAction' ), ['edit', 'submit'] ) !== -1 ) {
 
        mw.loader.using( 'user.options', function () {
 
                if ( mw.user.options.get('usebetatoolbar') ) {
 
                        mw.loader.using( 'ext.wikiEditor.toolbar', function () {
 
                                $(document).ready( customizeToolbar );
 
                        } );
 
                }
 
        } );
 
}
 
  
//See http://ru.wikipedia.org/wiki/project:code
+
$btn.text( isExpanded ? expandCaption : collapseCaption );
+
$rows.slice( 1 ).each( function () {
importScript_ = importScript
+
$( this ).css( 'display', cssDisplay );
importScript = function (page, proj){
+
} );
if (!proj) importScript_(page)
 
else {
 
  if (proj.indexOf('.')==-1) proj += '.wikipedia.org'
 
  importScriptURI('http://'+proj+'/w/index.php?action=raw&ctype=text/javascript&title='+encodeURIComponent(page.replace(/ /g,'_')))
 
}
 
 
}
 
}
  
//Collapsiblе: [[ВП:СБ]]
+
// div.NavFrame
 
+
var navFrameExpandCaption = '[' + expandCaption + ']',
var hasClass = (function (){
+
navFrameCollapseCaption = '[' + collapseCaption + ']';
var reCache = {}
 
return function (element, className){
 
  return (reCache[className] ? reCache[className] : (reCache[className] = new RegExp("(?:\\s|^)" + className + "(?:\\s|$)"))).test(element.className)
 
  }
 
})()
 
 
 
function collapsibleTables(){
 
var Table, HRow,  HCell, btn, a, tblIdx = 0, colTables = []
 
var allTables = document.getElementsByTagName('table')
 
for (var i=0; Table = allTables[i]; i++){
 
  if (!hasClass(Table, 'collapsible')) continue
 
  if (!(HRow=Table.rows[0])) continue
 
  if (!(HCell=HRow.getElementsByTagName('th')[0])) continue
 
  Table.id = 'collapsibleTable' + tblIdx
 
  btn = document.createElement('span')
 
  btn.style.cssText = 'float:right; font-weight:normal; font-size:smaller'
 
  a = document.createElement('a')
 
  a.id = 'collapseButton' + tblIdx
 
  a.href = 'javascript:collapseTable(' + tblIdx + ');'
 
  a.style.color = HCell.style.color
 
  a.appendChild(document.createTextNode(NavigationBarHide))
 
  btn.appendChild(a)
 
  HCell.insertBefore(btn, HCell.childNodes[0])
 
  colTables[tblIdx++] = Table
 
}
 
for (var i=0; i < tblIdx; i++)
 
  if ((tblIdx > NavigationBarShowDefault && hasClass(colTables[i], 'autocollapse')) || hasClass(colTables[i], 'collapsed'))
 
    collapseTable(i)
 
}
 
  
function collapseTable (idx){
+
// Изолируем код из глобальной области видимости
var Table = document.getElementById('collapsibleTable' + idx)
+
( function () {
var btn = document.getElementById('collapseButton' + idx)
+
function collapsibleDivs( $content ) {
if (!Table || !btn) return false
+
var navFrameIndex = 0,
var Rows = Table.rows
+
navFrames = [],
var isShown = (btn.firstChild.data == NavigationBarHide)
+
i;
btn.firstChild.data = isShown ?  NavigationBarShow : NavigationBarHide
 
var disp = isShown ? 'none' : Rows[0].style.display
 
for (var i=1; i < Rows.length; i++)
 
    Rows[i].style.display = disp
 
}
 
  
function collapsibleDivs(){
+
$content.find( 'div' ).each( function () {
var navIdx = 0, colNavs = [], i, NavFrame
+
var $div = $( this );
var divs = document.getElementById('content').getElementsByTagName('div')
+
if ( $div.hasClass( 'NavFrame' ) ) {
for (i=0; NavFrame = divs[i]; i++) {
+
var $btn = $( '<a>' )
  if (!hasClass(NavFrame, 'NavFrame')) continue
+
.addClass( 'NavToggle' )
  NavFrame.id = 'NavFrame' + navIdx
+
.attr( 'href', 'javascript:' )
  var a = document.createElement('a')
+
.text( navFrameCollapseCaption )
  a.className = 'NavToggle'
+
.click( navToggleClickHandler );
  a.id = 'NavToggle' + navIdx
+
$div.children( '.NavHead' ).append( $btn );
  a.href = 'javascript:collapseDiv(' + navIdx + ');'
+
navFrames[ navFrameIndex++ ] = $div;
  a.appendChild(document.createTextNode(NavigationBarHide))
+
}
  for (var j=0; j < NavFrame.childNodes.length; j++)
+
} );
    if (hasClass(NavFrame.childNodes[j], 'NavHead'))
+
for ( i = 0; i < navFrameIndex; i++ ) {
      NavFrame.childNodes[j].appendChild(a)
+
if ( navFrames[ i ].hasClass( 'collapsed' ) ||
  colNavs[navIdx++] = NavFrame
+
( navFrameIndex > NavigationBarShowDefault &&
}
+
!navFrames[ i ].hasClass( 'expanded' )
for (i=0; i < navIdx; i++)
+
)
  if ((navIdx > NavigationBarShowDefault && !hasClass(colNavs[i], 'expanded')) || hasClass(colNavs[i], 'collapsed'))
+
) {
    collapseDiv(i)
+
toggleDiv( navFrames[ i ] );
}
+
}
 +
}
 +
}
  
function collapseDiv(idx) {
+
mw.hook( 'wikipage.content' ).add( collapsibleDivs );
var div = document.getElementById('NavFrame' + idx)
 
var btn = document.getElementById('NavToggle' + idx)
 
if (!div || !btn) return false
 
var isShown = (btn.firstChild.data == NavigationBarHide)
 
btn.firstChild.data = isShown ? NavigationBarShow : NavigationBarHide
 
var disp = isShown ? 'none' : 'block'
 
for (var child = div.firstChild; child != null;  child = child.nextSibling)
 
  if (hasClass(child, 'NavPic') || hasClass(child, 'NavContent'))
 
      child.style.display = disp
 
}
 
  
 +
function navToggleClickHandler() {
 +
var $btn = $( this );
 +
toggleDiv( $btn.closest( '.NavFrame' ), $btn );
 +
}
  
 +
function toggleDiv( $div, $btn ) {
 +
$btn = $btn || $div.find( '.NavToggle' ).first();
 +
if ( !$div.length || !$btn.length ) return false;
 +
var isExpanded = ( $btn.text() === navFrameCollapseCaption );
 +
$btn.text( isExpanded ? navFrameExpandCaption : navFrameCollapseCaption );
 +
$div.children( '.NavContent, .NavPic' ).each( function () {
 +
$( this ).css( 'display', isExpanded ? 'none' : 'block' );
 +
} );
 +
}
  
//Execution
+
/**
mw.loader.using( 'mediawiki.util', function() {
+
* Загрузка скриптов через систему подгаджетов
 +
*/
 +
var namespaceNumber = mw.config.get( 'wgNamespaceNumber' );
  
 +
// Скрипты для служебных страниц
 +
if ( namespaceNumber === -1 ) {
 +
var specialGadgets = [
 +
'Abusefilter',
 +
'Block',
 +
'Log',
 +
'Movepage',
 +
'Newpages',
 +
'Search',
 +
'Upload'
 +
];
 +
var canonicalSpecialPageName = mw.config.get( 'wgCanonicalSpecialPageName' );
 +
if ( specialGadgets.indexOf( canonicalSpecialPageName ) > -1 ) {
 +
mw.loader.load( 'ext.gadget.common-special-' + canonicalSpecialPageName.toLowerCase() );
 +
}
 +
} else {
 +
// Скрипты для пространств имён
 +
var namespaceGadgets = {
 +
6: [ 'ext.gadget.common-namespace-file' ]
 +
};
  
if (wgCanonicalNamespace == 'Special'){
+
if ( namespaceGadgets[ namespaceNumber ] ) {
 +
mw.loader.load( namespaceGadgets[ namespaceNumber ] );
 +
}
 +
}
 +
}() );
  
  if (/^(Uplo|Sear|Stat|Spec|Abus|Prefe|Move|Watch|Newp)/i.test(wgCanonicalSpecialPageName))
+
/**
  importMW(wgCanonicalSpecialPageName)
+
* Старые коды
 +
  */
 +
if ( navigator.platform.indexOf( 'Win' ) !== -1 ) {
 +
mw.loader.using( 'mediawiki.util' ).done( function () {
 +
mw.util.addCSS( '.IPA, .Unicode { font-family: "Arial Unicode MS", "Lucida Sans Unicode"; }' );
 +
} );
 +
}
  
}else switch (wgAction){
+
/**
 +
* Выполнение скриптов из пространства MediaWiki, указанных в URL
 +
* См. также https://www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
 +
*/
 +
var withJS = location.href.match( /[&?]withjs=((mediawiki:)?([^&<>=#]+\.js))/i );
 +
if ( withJS ) {
 +
importScript_( 'MediaWiki:' + withJS[3] );
 +
}
  
  case 'history': importMW('History'); break
+
/**
 +
  * Код, который нужно выполнить как можно раньше. Он выполняется, если загружен подвал страницы,
 +
* иначе же ждёт наступления события wikipage.content (см. выше определение runAsEarlyAsPossible
 +
* и ниже про wikipage.content).
 +
*/
 +
runAsEarlyAsPossible( function () {
 +
/**
 +
* {{выполнить скрипт}}
 +
*/
 +
$( '.executeJS' ).each( function () {
 +
var names = $( this ).data( 'scriptnames' );
 +
if (names) {
 +
names.split( ' ' ).forEach( function ( name ) {
 +
name = name.replace( /[^\w_-]/g, '' );
 +
if ( name ) {
 +
importScript( 'MediaWiki:Script/' + name + '.js' );
 +
}
 +
} );
 +
}
 +
} );
  
case 'delete': importMW('Deletepage'); break
+
/**
 +
* Чтобы ссылки на очистку кэша не требовали подтверждения (они должны быть помещены в тег с классом
 +
* purgelink и именем страницы в атрибуте data-pagename, например как в шаблоне {{очистить кэш}})
 +
*/
 +
$( '.purgelink a' ).click( function ( e ) {
 +
mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).done( function () {
 +
var pageName = $( this ).parent( '.purgelink' ).data( 'pagename' ) || mw.config.get( 'wgPageName' );
 +
new mw.Api().post( {
 +
action: 'purge',
 +
titles: pageName
 +
} ).then( function () {
 +
var url = mw.util.getUrl( pageName );
 +
if ( e.ctrlKey ) {
 +
if ( !window.open( url ) ) {
 +
location.assign( url );
 +
}
 +
} else {
 +
location.assign( url );
 +
}
 +
}, function () {
 +
mw.notify( 'Не удалось очистить кэш.', { type: 'error' } );
 +
} );
 +
e.preventDefault();
 +
} );
 +
} );
 +
}, $( '#footer' ), mw.hook( 'wikipage.content' ).add );
  
case 'edit': case 'submit': importMW('Editpage') //and continue with the default: view, purge
+
// По какой-то причине фикс для FlaggedRevs работает только при использовании then(), но не done().
 +
mw.loader.using( 'ext.visualEditor.desktopArticleTarget.init' ).then( function () {
 +
/**
 +
* Исправление поведения FlaggedRevs в сочетании с визуальным редактором, чтобы
 +
* в стабилизированных статьях на правку в визреде открывалась последняя версия, что
 +
* соответствует поведению обычного редактора.
 +
*/
 +
runAsEarlyAsPossible( function () {
 +
function fixEditLinksForStableRevs( removeClickHandlers ) {
 +
if ( $( '#ca-view.selected' ).length ) {
 +
// При выходе из визреда (сохранении или переключении) ссылки работают правильно
 +
// и убирать обработчики событий нет нужды — только исправить URL’ы на случай
 +
// открытия правки в новой вкладке.
 +
if ( removeClickHandlers ) {
 +
$( '#ca-ve-edit, .mw-editsection-visualeditor' ).off( 'click' );
 +
}
 +
$( '#ca-ve-edit a, .mw-editsection-visualeditor' ).each( function () {
 +
var href = $( this ).attr( 'href' );
 +
if ( !/[?&]stable=0/.test( href ) ) {
 +
$( this ).attr( 'href',
 +
href
 +
.replace( /&veaction=edit/, '&stable=0&veaction=edit' )
 +
.replace( /&oldid=\d+/, '' )
 +
);
 +
}
 +
} );
 +
}
 +
}
  
default:
+
// Не включаем сюда проверку на наличие #ca-view.selected, чтобы не вычёркивать случай,
 +
// когда визред открыт без Ajax и по выходу из него нужно заменить URL’ы в ссылках.
 +
if ( $( '#ca-current' ).length && !/[?&](oldid|diff)=\d+/.test( location.search ) ) {
 +
fixEditLinksForStableRevs( true );
 +
 +
mw.hook( 've.deactivationComplete' ).add( function () {
 +
fixEditLinksForStableRevs( false );
 +
} );
 +
}
 +
} );
 +
} );
  
  $(editZeroSection)
+
mw.hook( 've.loadModules' ).add( function( addPlugin ) {
  addOnloadHook(collapsibleDivs)
+
/**
  addOnloadHook(collapsibleTables)
+
* Поддержка Викификатора в новом режиме вики-текста aka 2017 wikitext editor
  mw.loader.load('//meta.wikimedia.org/w/index.php?title=MediaWiki:Wikiminiatlas.js&action=raw&ctype=text/javascript&smaxage=21600&maxage=86400')
+
*/
  if( document.location && document.location.protocol == 'https:' )
+
addPlugin( function () {
    importMW('Secure')
+
return mw.loader.using( 'ext.gadget.wikificator' );
  if (navigator.platform.indexOf('Win') != -1)
+
} );
    mw.util.addCSS('.IPA, .Unicode { font-family: "Arial Unicode MS", "Lucida Sans Unicode"; }')
+
} );
  
 +
/**
 +
* {{TOC hidden}}
 +
*/
 +
function TOChidden() {
 +
$( '.tochidden-wrapper > #toc > #toctogglecheckbox' ).prop('checked', true );
 +
$( '.tochidden-wrapper' ).attr( "class", "toc-wrapper" );
 +
}
  
 
+
runAsEarlyAsPossible( function () {
  switch( wgNamespaceNumber ){
+
if ( $( '.tochidden-wrapper' ).length ) {
    case 0: case 100:
+
mw.loader.using( [ 'mediawiki.cookie' ] ).done( function () {
      $(LinkFA)
+
if ( mw.cookie.get( 'hidetoc' ) === null ) {
      importMW('Osm')
+
$.when( mw.loader.using( [ 'mediawiki.toc' ] ), $.ready ).then( TOChidden );
      if( wgArticleId==4401 ) importMW('Mainpage')
+
}
      break
+
} );
    case 6:
+
}
      importMW('Filepage')
+
}, $( '#toc' ), mw.hook( 'wikipage.content' ).add );
      break
 
  }   
 
  
}
+
/**
 +
* Код, выполняемый по событию wikipage.content (его обработчики выполняются раньше колбэков для $,
 +
* хотя в глубине это одно и то же событие, просто колбэк, инициирующий wikipage.content, становится
 +
* в очередь раньше). Так как wikipage.content инициируется после обновления страницы в результате
 +
* Ajax-запросов (например, гаджетом быстрого предпросмотра), не добавляйте сюда коды, которые
 +
* должны гарантированно выполниться не более одного раза на странице.
 +
*/
 +
mw.hook( 'wikipage.content' ).add( function () {
 +
/**
 +
* Отключение обтекания раздела примечаний, если в нём есть колонки.
 +
* Короткие (до 15 ссылок, если общее число символов не менее 3000) списки примечаний обтекаются
 +
* только справа.
 +
*/
 +
$( '.reflist.columns' ).each( function () {
 +
var clear = 'both',
 +
$refs = $( this ).find( 'ol.references > li' );
 +
if ( $refs.length <= 10 ) return;
 +
if ( $refs.length <= 15 && $refs.text().length < 3000 ) {
 +
clear = 'left';
 +
}
 +
$( this )
 +
.prevUntil( 'h1, h2, h3, h4, h5, h6' )
 +
.addBack()
 +
.first()
 +
.prev()
 +
.css( 'clear', clear );
 +
} );
  
 +
/**
 +
* Imagemap Highlight
 +
*/
 +
// На странице есть как минимум один элемент .imageMapHighlighter, а браузер поддерживает <canvas>
 +
if ( $( '.imageMapHighlighter' ).length && $( '<canvas>' )[ 0 ].getContext ) {
 +
importScript( 'MediaWiki:Imagemap-Highlight.js' );
 +
}
  
if( wgUserName ){
+
/**
  if( wgNamespaceNumber==2 && wgTitle.indexOf(wgUserName)==0 && wgArticleId==0 && /\/skin\.(js|css)$/.test(wgTitle) )
+
* imgToggle
    window.location.href = window.location.href.replace(/skin\.(css|js)$/, skin+'.$1')
+
*/
}else{ //hide FlaggedRevs
+
// На странице есть как минимум один элемент div.img_toggle
  mw.util.addCSS('#mw-fr-revisiontag {display:none}')
+
if ( $( 'div.img_toggle' ).length ) {
}
+
mw.loader.load( 'ext.gadget.imgToggle' );
 +
}
  
 +
/**
 +
* Авторазбиение списков на колонки. Будет работать только для однострочных списков. 35em
 +
* (из Mediawiki:Common.css) является предварительным числом, а фактическое будет посчитано исходя
 +
* из ширины элементов. Должно использоваться только для UL внутри DIV. Пример использования —
 +
* шаблон {{Wikidata/SisterCities}}.
 +
*/
 +
$("div.autocolumns").each(function(d, div) {
 +
var parentWidth = $(div).parent()[0].offsetWidth;
 +
if (!parentWidth) return;
  
// ВП:СО, кроме статей  В Контакте, Одноклассники и Facebook
+
var maxWidth = 0;
if (wgArticleId!=639373 && wgArticleId!=932117 && wgArticleId!=1297302 && wgArticleId!=25133866)
+
var elements = 0;
importMW('Wikibugs')
+
$(div).find("ul>li").each(function(l, li) {
 +
elements++;
 +
var jLi = $(li);
 +
if (jLi.children().length != jLi.contents().length)
 +
jLi.wrapInner(document.createElement("span"));
  
   
+
var liWidth = 0;
//extra scripts
+
jLi.children().each(function(c, child) {
 +
liWidth += child.offsetWidth;
 +
});
 +
if (liWidth > maxWidth)
 +
maxWidth = liWidth;
 +
});
 +
if ( maxWidth === 0 ) return;
 +
// UL/LI bullet width + padding
 +
maxWidth += 22.5 * 2;
  
var withJS = document.URL.match(/[&?]withjs=((mediawiki:)?([^&#]+))/i)
+
var maxColumns = "" + Math.ceil( elements / 5 );
if( withJS ) importScript_('MediaWiki:'+withJS[3])
+
$(div).css({"-moz-columns": maxWidth + "px " + maxColumns, "columns" : maxWidth + "px " + maxColumns});
 +
});
 +
});
  
var execJS = document.getElementById('executeJS')
+
/**
if( execJS )
+
* Кнопки описания правок для визуального редактора
  $.each( execJS.className.split(' '), function(i, sc){
+
  */
    sc = $.trim( sc.replace(/[^\w ]/g,'') )
+
mw.hook( 've.activationComplete' ).add( function () {
    if( sc ) importMW('Script/' + sc)
+
mw.loader.load( 'ext.gadget.summaryButtons' );
  })
+
} );

Версия 01:31, 28 октября 2022

/**
 * Код MediaWiki:Common.js безусловно загружается всем пользователям на всех страницах. Во избежание
 * отправки лишних запросов по возможности не используйте здесь mw.loader.using с модулями, которые
 * не загружаются по умолчанию (см.
 * [[Обсуждение MediaWiki:Common.js#Список модулей, загружаемых по умолчанию]]). В таком случае
 * лучше создать скрытый гаджет, загружаемый по умолчанию, и добавить ему нужные модули в качестве
 * зависимостей.
 */

/**
 * Локальная функция загрузки скриптов с поддержкой указания проекта
 */
var importScript_ = importScript;
importScript = function ( page, proj ) {
	if ( !proj ) {
		importScript_( page );
	} else {
		if ( proj.indexOf( '.' ) === -1 ) {
			proj += 'celeste-rus.ru';
		}
		mw.loader.using( 'mediawiki.util' ).done( function () {
			mw.loader.load( '//' + proj + '/index.php?title=' + mw.util.wikiUrlencode( page ) +
				'&action=raw&ctype=text/javascript' );
		} );
	}
};

/**
 * Часто те или иные манипуляции со страницей нужно выполнить как можно раньше, но нет гарантии, что
 * к моменту выполнения кода нужный участок DOM готов, а событие полной загрузки страницы происходит
 * слишком поздно. В этой функции проверяется наличие элемента $testElement и в случае успеха
 * функция-колбэк выполняется, иначе же её выполнение поручается другой функции. Если элемент
 * в $testElement имеет содержимое, правильнее указать следующий за ним элемент, чтобы быть
 * уверенным, что он загрузился до конца. Имейте в виду, что разные скины часто используют разные
 * названия классов и идентификаторов.
 */
function runAsEarlyAsPossible( callback, $testElement, func ) {
	func = func || $;
	$testElement = $testElement || $( '#footer' );

	if ( $testElement.length ) {
		callback();
	} else {
		func( callback );
	}
}

/**
 * Настройка обработки «е» и «ё» при сортировке в таблицах
 */
mw.config.set( 'tableSorterCollation', { 'Ё': 'Е', 'ё': 'е' } );

/**
 * Строки. Иноязычный интерфейс предположительно включают весьма редко, поэтому раздувать этот
 * список не стоит. При необходимости добавить много сообщений во много языков можно использовать
 * механизм системных сообщений (= страниц в пространстве MediaWiki, у которых могут быть суффиксы
 * типа /en). См., как их получение реализовано в MediaWiki:Gadget-sidebarRelated.js.
 */
var expandCaption, collapseCaption, zeroSectionTip;
if ( mw.config.get( 'wgUserLanguage' ) === 'en' ) {
	expandCaption = 'show';
	collapseCaption = 'hide';
	zeroSectionTip = 'Edit lead section';
} else {
	expandCaption = 'показать';
	collapseCaption = 'скрыть';
	zeroSectionTip = 'Править преамбулу';
}

/**
 * Сворачиваемые блоки
 */
// Число раскрытых по умолчанию навигационных (и не только) шаблонов, если им задан параметр
// autocollapse. Участники могут переопределять это значение в личных JS.
var NavigationBarShowDefault;
if ( typeof NavigationBarShowDefault === 'undefined' ) {
	NavigationBarShowDefault = 1;
}

// table.collapsible
// collapsibleTablesItrIdx - временное решние, чтобы не дублировались id,
// если во время срабатывания хука 'wikipage.content' добавляются новые сворачиваемые блоки
var collapsibleTablesItrIdx = 0;
	
function collapsibleTables( $content ) {
	var $btn,
		$a,
		tblIdx = collapsibleTablesItrIdx,
		navboxCount = 0,
		notNavboxCount = 0,
		colTables = [],
		$Tables = $content.find( 'table' );

	$Tables.each( function ( i, table ) {
		if ( $( table ).hasClass( 'collapsible' ) ) {
			var $table = $( this ),
				$row = $table.find( 'tr' ).first(),
				$cell = $row.find( 'th' ).first();
			if ( !$cell.length ) {
				return;
			}
			$table.attr( 'id', 'collapsibleTable' + tblIdx );
			$btn = $( '<span>' ).addClass( 'collapseButton' );
			$a = $( '<a>' )
				.attr( 'id', 'collapseButton' + tblIdx )
				.attr( 'href', 'javascript:collapseTable(' + tblIdx + ');' )
				// Изменяем цвет ссылки, только если цвет текста в навбоксе нестандартный
				.css( 'color', $cell.css( 'color' ) === $( '.mw-body' ).css( 'color' ) ? 'auto' :
					$cell.css( 'color' ) )
				.text( collapseCaption );
			$btn
				.append( '[' )
				.append( $a )
				.append( ']' );
			if ( $cell.contents().length ) {
				$btn.insertBefore( $cell.contents().first() );
			} else {
				$btn.appendTo( $cell );
			}
			// hasClass( 'navbox' ) — временное решение для навшаблонов, ещё не переведённых
			// на {{Навигационная таблица}} (также ниже)
			if ( $table.hasClass( 'navbox-inner' ) || $table.hasClass( 'navbox' ) ) {
				navboxCount++;
			} else {
				notNavboxCount++;
			}
			colTables[tblIdx++] = $table;
		}
	} );
	for ( var i = collapsibleTablesItrIdx; i < tblIdx; i++ ) {
		if ( colTables[i].hasClass( 'collapsed' ) ||
			( colTables[i].hasClass( 'autocollapse' ) &&
				( ( ( colTables[i].hasClass( 'navbox-inner' ) || colTables[i].hasClass( 'navbox' ) ) &&
						navboxCount > NavigationBarShowDefault ) ||
					( !( colTables[i].hasClass( 'navbox-inner' ) || colTables[i].hasClass( 'navbox' ) ) &&
						notNavboxCount > NavigationBarShowDefault ) ) ) )
		{
			collapseTable( i );
		}
	}
	collapsibleTablesItrIdx = tblIdx;
	// Нужно переписать код на "mw-collapsible", и заменить использование хука на "wikipage.collapsibleContent"
	mw.hook( 'common.collapsibleContent' ).fire( colTables );
}

mw.hook( 'wikipage.content' ).add( collapsibleTables );

function collapseTable( idx ) {
	var $table = $( '#collapsibleTable' + idx ),
		$rows = $table.children().children( 'tr' ),
		$btn = $( '#collapseButton' + idx );
	if ( !$table.length || !$rows.length || !$btn.length ) {
		return false;
	}

	var isExpanded = ( $btn.text() === collapseCaption ),
		cssDisplay = isExpanded ? 'none' : $rows.first().css( 'display' );

	$btn.text( isExpanded ? expandCaption : collapseCaption );
	$rows.slice( 1 ).each( function () {
		$( this ).css( 'display', cssDisplay );
	} );
}

// div.NavFrame
var navFrameExpandCaption = '[' + expandCaption + ']',
	navFrameCollapseCaption = '[' + collapseCaption + ']';

// Изолируем код из глобальной области видимости
( function () {
	function collapsibleDivs( $content ) {
		var navFrameIndex = 0,
			navFrames = [],
			i;

		$content.find( 'div' ).each( function () {
			var $div = $( this );
			if ( $div.hasClass( 'NavFrame' ) ) {
				var $btn = $( '<a>' )
					.addClass( 'NavToggle' )
					.attr( 'href', 'javascript:' )
					.text( navFrameCollapseCaption )
					.click( navToggleClickHandler );
				$div.children( '.NavHead' ).append( $btn );
				navFrames[ navFrameIndex++ ] = $div;
			}
		} );
		for ( i = 0; i < navFrameIndex; i++ ) {
			if ( navFrames[ i ].hasClass( 'collapsed' ) ||
				( navFrameIndex > NavigationBarShowDefault &&
					!navFrames[ i ].hasClass( 'expanded' )
				)
			) {
				toggleDiv( navFrames[ i ] );
			}
		}
	}

	mw.hook( 'wikipage.content' ).add( collapsibleDivs );

	function navToggleClickHandler() {
		var $btn = $( this );
		toggleDiv( $btn.closest( '.NavFrame' ), $btn );
	}

	function toggleDiv( $div, $btn ) {
		$btn = $btn || $div.find( '.NavToggle' ).first();
		if ( !$div.length || !$btn.length ) return false;
		var isExpanded = ( $btn.text() === navFrameCollapseCaption );
		$btn.text( isExpanded ? navFrameExpandCaption : navFrameCollapseCaption );
		$div.children( '.NavContent, .NavPic' ).each( function () {
			$( this ).css( 'display', isExpanded ? 'none' : 'block' );
		} );
	}

	/**
	 * Загрузка скриптов через систему подгаджетов
	 */
	var namespaceNumber = mw.config.get( 'wgNamespaceNumber' );

	// Скрипты для служебных страниц
	if ( namespaceNumber === -1 ) {
		var specialGadgets = [
			'Abusefilter',
			'Block',
			'Log',
			'Movepage',
			'Newpages',
			'Search',
			'Upload'
		];
		var canonicalSpecialPageName = mw.config.get( 'wgCanonicalSpecialPageName' );
		if ( specialGadgets.indexOf( canonicalSpecialPageName ) > -1 ) {
			mw.loader.load( 'ext.gadget.common-special-' + canonicalSpecialPageName.toLowerCase() );
		}
	} else {
		// Скрипты для пространств имён
		var namespaceGadgets = {
			6: [ 'ext.gadget.common-namespace-file' ]
		};

		if ( namespaceGadgets[ namespaceNumber ] ) {
			mw.loader.load( namespaceGadgets[ namespaceNumber ] );
		}
	}
}() );

/**
 * Старые коды
 */
if ( navigator.platform.indexOf( 'Win' ) !== -1 ) {
	mw.loader.using( 'mediawiki.util' ).done( function () {
		mw.util.addCSS( '.IPA, .Unicode { font-family: "Arial Unicode MS", "Lucida Sans Unicode"; }' );
	} );
}

/**
 * Выполнение скриптов из пространства MediaWiki, указанных в URL
 * См. также https://www.mediawiki.org/wiki/Snippets/Load_JS_and_CSS_by_URL
 */
var withJS = location.href.match( /[&?]withjs=((mediawiki:)?([^&<>=#]+\.js))/i );
if ( withJS ) {
	importScript_( 'MediaWiki:' + withJS[3] );
}

/**
 * Код, который нужно выполнить как можно раньше. Он выполняется, если загружен подвал страницы,
 * иначе же ждёт наступления события wikipage.content (см. выше определение runAsEarlyAsPossible
 * и ниже про wikipage.content).
 */
runAsEarlyAsPossible( function () {
	/**
	 * {{выполнить скрипт}}
	 */
	$( '.executeJS' ).each( function () {
		var names = $( this ).data( 'scriptnames' );
		if (names) {
			names.split( ' ' ).forEach( function ( name ) {
				name = name.replace( /[^\w_-]/g, '' );
				if ( name ) {
					importScript( 'MediaWiki:Script/' + name + '.js' );
				}
			} );
		}
	} );

	/**
	 * Чтобы ссылки на очистку кэша не требовали подтверждения (они должны быть помещены в тег с классом
	 * purgelink и именем страницы в атрибуте data-pagename, например как в шаблоне {{очистить кэш}})
	 */
	$( '.purgelink a' ).click( function ( e ) {
		mw.loader.using( [ 'mediawiki.api', 'mediawiki.util' ] ).done( function () {
			var pageName = $( this ).parent( '.purgelink' ).data( 'pagename' ) || mw.config.get( 'wgPageName' );
			new mw.Api().post( {
				action: 'purge',
				titles: pageName
			} ).then( function () {
				var url = mw.util.getUrl( pageName );
				if ( e.ctrlKey ) {
					if ( !window.open( url ) ) {
						location.assign( url );
					}
				} else {
					location.assign( url );
				}
			}, function () {
				mw.notify( 'Не удалось очистить кэш.', { type: 'error' } );
			} );
			e.preventDefault();
		} );
	} );
}, $( '#footer' ), mw.hook( 'wikipage.content' ).add );

// По какой-то причине фикс для FlaggedRevs работает только при использовании then(), но не done().
mw.loader.using( 'ext.visualEditor.desktopArticleTarget.init' ).then( function () {
	/**
	 * Исправление поведения FlaggedRevs в сочетании с визуальным редактором, чтобы
	 * в стабилизированных статьях на правку в визреде открывалась последняя версия, что
	 * соответствует поведению обычного редактора.
	 */
	runAsEarlyAsPossible( function () {
		function fixEditLinksForStableRevs( removeClickHandlers ) {
			if ( $( '#ca-view.selected' ).length ) {
				// При выходе из визреда (сохранении или переключении) ссылки работают правильно
				// и убирать обработчики событий нет нужды — только исправить URL’ы на случай
				// открытия правки в новой вкладке.
				if ( removeClickHandlers ) {
					$( '#ca-ve-edit, .mw-editsection-visualeditor' ).off( 'click' );
				}
				$( '#ca-ve-edit a, .mw-editsection-visualeditor' ).each( function () {
					var href = $( this ).attr( 'href' );
					if ( !/[?&]stable=0/.test( href ) ) {
						$( this ).attr( 'href',
							href
								.replace( /&veaction=edit/, '&stable=0&veaction=edit' )
								.replace( /&oldid=\d+/,  '' )
						);
					}
				} );
			}
		}

		// Не включаем сюда проверку на наличие #ca-view.selected, чтобы не вычёркивать случай,
		// когда визред открыт без Ajax и по выходу из него нужно заменить URL’ы в ссылках.
		if ( $( '#ca-current' ).length && !/[?&](oldid|diff)=\d+/.test( location.search ) ) {
			fixEditLinksForStableRevs( true );
		
			mw.hook( 've.deactivationComplete' ).add( function () {
				fixEditLinksForStableRevs( false );
			} );
		}
	} );
} );

mw.hook( 've.loadModules' ).add( function( addPlugin ) {
	/**
	 * Поддержка Викификатора в новом режиме вики-текста aka 2017 wikitext editor
	 */
	addPlugin( function () {
		return mw.loader.using( 'ext.gadget.wikificator' );
	} );
} );

/**
 * {{TOC hidden}}
 */
function TOChidden() {
	$( '.tochidden-wrapper > #toc > #toctogglecheckbox' ).prop('checked', true );
	$( '.tochidden-wrapper' ).attr( "class", "toc-wrapper" );
}

runAsEarlyAsPossible( function () {
	if ( $( '.tochidden-wrapper' ).length ) {
		mw.loader.using( [ 'mediawiki.cookie' ] ).done( function () {
			if ( mw.cookie.get( 'hidetoc' ) === null ) {
				$.when( mw.loader.using( [ 'mediawiki.toc' ] ), $.ready ).then( TOChidden );
			}
		} );
	}
}, $( '#toc' ), mw.hook( 'wikipage.content' ).add );

/**
 * Код, выполняемый по событию wikipage.content (его обработчики выполняются раньше колбэков для $,
 * хотя в глубине это одно и то же событие, просто колбэк, инициирующий wikipage.content, становится
 * в очередь раньше). Так как wikipage.content инициируется после обновления страницы в результате
 * Ajax-запросов (например, гаджетом быстрого предпросмотра), не добавляйте сюда коды, которые
 * должны гарантированно выполниться не более одного раза на странице.
 */
mw.hook( 'wikipage.content' ).add( function () {
	/**
	 * Отключение обтекания раздела примечаний, если в нём есть колонки.
	 * Короткие (до 15 ссылок, если общее число символов не менее 3000) списки примечаний обтекаются
	 * только справа.
	 */
	$( '.reflist.columns' ).each( function () {
		var clear = 'both',
			$refs = $( this ).find( 'ol.references > li' );
		if ( $refs.length <= 10 ) return;
		if ( $refs.length <= 15 && $refs.text().length < 3000 ) {
			clear = 'left';
		}
		$( this )
			.prevUntil( 'h1, h2, h3, h4, h5, h6' )
			.addBack()
			.first()
			.prev()
			.css( 'clear', clear );
	} );

	/**
	 * Imagemap Highlight
	 */
	// На странице есть как минимум один элемент .imageMapHighlighter, а браузер поддерживает <canvas>
	if ( $( '.imageMapHighlighter' ).length && $( '<canvas>' )[ 0 ].getContext ) {
		importScript( 'MediaWiki:Imagemap-Highlight.js' );
	}

	/**
	 * imgToggle
	 */
	// На странице есть как минимум один элемент div.img_toggle
	if ( $( 'div.img_toggle' ).length ) {
		mw.loader.load( 'ext.gadget.imgToggle' );
	}

	/**
	 * Авторазбиение списков на колонки. Будет работать только для однострочных списков. 35em
	 * (из Mediawiki:Common.css) является предварительным числом, а фактическое будет посчитано исходя
	 * из ширины элементов. Должно использоваться только для UL внутри DIV. Пример использования —
	 * шаблон {{Wikidata/SisterCities}}.
	 */
	$("div.autocolumns").each(function(d, div) {
		var parentWidth = $(div).parent()[0].offsetWidth;
		if (!parentWidth) return;

		var maxWidth = 0;
		var elements = 0;
		$(div).find("ul>li").each(function(l, li) {
			elements++;
			var jLi = $(li);
			if (jLi.children().length != jLi.contents().length)
				jLi.wrapInner(document.createElement("span"));

			var liWidth = 0;
			jLi.children().each(function(c, child) {
				liWidth += child.offsetWidth;
			});
			if (liWidth > maxWidth)
				maxWidth = liWidth;
		});
		if ( maxWidth === 0 ) return;
		// UL/LI bullet width + padding
		maxWidth += 22.5 * 2;

		var maxColumns = "" + Math.ceil( elements / 5 );
		$(div).css({"-moz-columns": maxWidth + "px " + maxColumns, "columns" : maxWidth + "px " + maxColumns});
	});
});

/**
 * Кнопки описания правок для визуального редактора
 */
mw.hook( 've.activationComplete' ).add( function () {
	mw.loader.load( 'ext.gadget.summaryButtons' );
} );