MediaWiki:Gadget-navboxFeaturedArticles.js (MediaWiki&Gadget-navboxFeaturedArticlesQjs)
Перейти к навигации
Перейти к поиску
JS-код ниже относится к гаджету: Отобразить или скрыть иконки статусных статей перед ссылками в навигационных шаблонах (править описание). Связанный CSS-файл: MediaWiki:Gadget-navboxFeaturedArticles.css. Его использует около 300 учётных записей.
После сохранения или недавних изменений очистите кэш браузера.
/**
* Navbox Featured Articles
*
* Author: Serhio Magpie
* Licenses: MIT, CC BY-SA
*/
// <nowiki>
( function () {
var _config = {
name: 'gadget-navboxFeaturedArticles',
optionsName: 'userjs-navboxFeaturedArticles-options',
pagename: 'MediaWiki:Gadget-navboxFeaturedArticles.js',
wikilink: '[[MediaWiki:Gadget-navboxFeaturedArticles.js]]',
wdAPI: 'https://www.wikidata.org/w/api.php',
wdLimit: 50,
wgDBname: mw.config.get( 'wgDBname' ),
wgPageName: mw.config.get( 'wgPageName' ),
commonsThumb: 'https://upload.wikimedia.org/wikipedia/commons/',
navboxSelector: '.navbox:not([data-name="External links"])',
gearSelector: '%navbox% .navbox-gear',
linkQuoteRegExp: /('|‘|"|«|“|„)$/,
linkSelector: '%navbox% a',
linkExcludeSelector: '%navbox% [data-nfa-badge="0"] a',
linkExcludeClasses: [ 'new', 'extiw', 'external', 'userlink' ],
badgeSelector: '%navbox% a[title="%title%"], %navbox% sup[title="%title%"]',
badgeSpaceCharacter: '\u2060',
badgeSizeMin: 8,
badgeSizeMax: 16,
badges: {
Q17437796: {
id: 'Q17437796',
name: 'featured',
title: 'Избранная статья',
titleAlias: [ 'Избранная статья, статья года' ],
link: 'Википедия:Избранные статьи',
image: {
default: '8/8b/Small_Skew_Star_SVG.svg',
modern: '0/08/Yellow_star_unboxed.svg'
},
alt: '✯'
},
Q17437798: {
id: 'Q17437798',
name: 'good',
title: 'Хорошая статья',
link: 'Википедия:Хорошие статьи',
image: {
default: '2/20/Blue_star_unboxed.svg',
modern: '2/20/Blue_star_unboxed.svg'
},
alt: '✯'
},
Q17559452: {
id: 'Q17559452',
name: 'recommended',
title: 'Добротная статья',
link: 'Википедия:Добротные статьи',
image: {
default: 'a/ae/Crystal_Clear_action_bookmark_Silver_approved.svg',
modern: '2/2b/Grey_star_unboxed.svg'
},
alt: '✯'
},
Q17506997: {
id: 'Q17506997',
name: 'list',
title: 'Избранный список',
titleAlias: [
'Этот список был признан избранным',
'Этот портал был признан избранным',
'Этот список или портал признан избранным',
'Избранный список или портал'
],
link: 'Википедия:Избранные списки и порталы',
image: {
default: '2/22/Feat_lists.svg',
modern: '2/22/Feat_lists.svg'
},
alt: '≛'
},
AOFY: {
id: 'AOFY',
name: 'aofy',
title: 'Статья года',
link: 'Википедия:Статьи года',
image: {
default: '/2/28/Статьи_года_Статья_года.svg',
modern: '/2/28/Статьи_года_Статья_года.svg'
},
alt: '✯'
}
}
},
_strings = {
'nfa-error-link-title': '$1: имя ссылки некорректно: $2',
'nfa-error-badge-link-title': '$1: имя статусной ссылки некорректно: $2',
'nfa-error-user-settings-read': '$1: не удалось получить настройки пользователя',
'nfa-template-view': 'Перейти к шаблону',
'nfa-template-settings': 'Настроить отображение статусов',
'nfa-settings-title': 'Иконки статусных статей',
'nfa-settings-save': 'Сохранить',
'nfa-settings-cancel': 'Отмена',
'nfa-settings-enable': 'Включить',
'nfa-settings-disable': 'Отключить',
'nfa-settings-done': 'Готово',
'nfa-settings-recommended': 'Отображать добротные статьи',
'nfa-settings-good': 'Отображать хорошие статьи',
'nfa-settings-featured': 'Отображать избранные статьи',
'nfa-settings-list': 'Отображать избранные списки',
'nfa-settings-style' : 'Стиль иконок',
'nfa-settings-style-default' : 'Классический',
'nfa-settings-style-modern' : 'Современный',
'nfa-settings-size': 'Размер иконки',
'nfa-settings-error': 'Не удалось сохранить настройки!'
},
_options = {
enabled: true,
recommended: true,
good: true,
featured: true,
list: true,
aofy: false,
style: 'modern',
size: 12
},
_userOptions = {},
_gears = [],
_pages = {},
_alias = {},
_links = [],
_badgeNodes = [],
_$context,
_isNavbox,
_settingsDialog;
/******* COMMON *******/
function inDOM( $node ) {
var node = $node.get( 0 );
return $.contains( document.documentElement, node );
}
/******* PAGE *******/
function Page ( title, isRedirect ) {
this.title = title;
this.isRedirect = isRedirect;
this.isProcessed = false;
this.hasBadge = false;
this.links = [];
_pages[this.title] = this;
}
Page.prototype.setProcessed = function ( status ) {
this.isProcessed = status;
};
Page.prototype.addLink = function ( link ) {
this.links.push( link );
};
Page.prototype.resolveRedirect = function ( title ) {
this.origTitle = this.title;
this.title = title;
this.isRedirect = false;
var page = _pages[this.title];
if ( page ) {
_alias[this.origTitle] = page;
$( this.links ).each( function () {
this.setParent( page );
} );
} else {
_alias[this.origTitle] = this;
_pages[this.title] = this;
}
delete _pages[this.origTitle];
};
Page.prototype.setBadge = function ( badge ) {
this.badge = badge;
this.hasBadge = true;
};
Page.prototype.renderLinkBadges = function () {
var that = this;
if ( !that.hasBadge ) {
return;
}
$( that.links ).each( function () {
var link = this;
if ( !link.hasBadge ) {
link.setBadge( that.badge );
} else {
link.toggleBadge();
}
} );
};
/******* LINK *******/
function Link( $node ) {
this.$node = $node;
this.isRedirect = $node.hasClass( 'mw-redirect' );
this.isSelf = $node.hasClass( 'selflink' );
this.hasBadge = false;
this.title = this.isSelf ? _config.wgPageName : $node.attr( 'title' );
// Skip new and external links from processing
var hasExcludeClass = _config.linkExcludeClasses.some( function ( className ) {
return $node.hasClass( className );
} );
if ( hasExcludeClass ) {
return;
}
// Skip images
var $children = $node.children( 'img' );
if ( $children.length !== 0 ) {
return;
}
// Skip links with empty titles
if ( typeof this.title === 'undefined' || this.title.length === 0 ) {
return;
}
// Normalize title
try {
var title = new mw.Title( this.title );
this.title = title.getPrefixedText();
this.namespace = title.getNamespaceId();
} catch ( e ) {
console.log( mw.msg( 'nfa-error-link-title', _config.wikilink, this.title ) );
}
// Process only main namespace
if ( typeof this.namespace === 'undefined' || this.namespace !== 0 ) {
return;
}
// Find parent page object or construct it
var page = _pages[this.title];
if ( !page ) {
page = _alias[this.title];
}
if ( !page ) {
page = new Page( this.title, this.isRedirect );
}
this.setParent( page );
_links.push( this );
}
Link.prototype.setParent = function ( page ) {
this.parent = page;
this.parent.addLink( this );
};
Link.prototype.setBadge = function ( badge ) {
this.badge = $.extend( {}, badge );
this.hasBadge = true;
this.toggleBadge();
};
Link.prototype.toggleBadge = function () {
if ( this.isBadgeShown ) {
this.detachBadge();
}
if ( _userOptions[this.badge.name] ) {
this.renderBadge();
}
};
Link.prototype.renderBadge = function () {
var imageStyle = this.badge.image[_userOptions.style] ? _userOptions.style : 'default';
this.badge.$image = $( '<img>' )
.attr( 'height', _userOptions.size )
.attr( 'alt', this.badge.alt )
.attr( 'src', this.badge.image[imageStyle] );
this.badge.$link = $( '<a>' )
.addClass( 'nfa__badge' )
.addClass( [ 'nfa__badge', this.badge.name ].join( '--' ) )
.attr( 'title', this.badge.title )
.attr( 'href', this.badge.url )
.append( this.badge.$image );
this.appendBadge();
this.badge.link = this.badge.$link.get( 0 );
_badgeNodes.push( this.badge.link );
};
Link.prototype.appendBadge = function () {
var beforeSibling, beforeContent,
$node = this.$node,
sibling = this.getSibling( $node ),
spacer;
this.isBadgeShown = true;
// If closest previous sibling is not exists, check parent node
if ( !sibling ) {
$node = $node.parent();
sibling = this.getSibling( $node );
}
// Insert bedge before closest to link quote character
if ( sibling && sibling.isTextNode && sibling.quote ) {
$node = $( sibling.node );
// Split previous sibling text line if contains not only one quote character
if ( sibling.content.length > 1 ) {
sibling.node.textContent = sibling.quote[0];
beforeContent = sibling.content.replace( _config.linkQuoteRegExp, '' );
beforeSibling = document.createTextNode( beforeContent );
$node.before( beforeSibling );
}
} else {
$node = this.$node;
}
$node.before( this.badge.$link );
// Add non-breaking space character between badge and link node
this.badge.spacer = document.createTextNode( _config.badgeSpaceCharacter );
$node.before( this.badge.spacer );
};
Link.prototype.getSibling = function ( $node ) {
var node = $node.get( 0 ).previousSibling,
sibling = {};
if ( !node ) {
return;
}
sibling.node = node,
sibling.content = sibling.node && sibling.node.textContent || '',
sibling.isTextNode = sibling.node && sibling.node.nodeType === Node.TEXT_NODE,
sibling.quote = sibling.content.match( _config.linkQuoteRegExp );
return sibling;
};
Link.prototype.detachBadge = function () {
var index;
if ( this.isBadgeShown ) {
this.isBadgeShown = false;
this.badge.$link.remove();
$( this.badge.spacer ).remove();
index = _badgeNodes.indexOf( this.badge.link );
if ( index > -1 ) {
_badgeNodes.splice( index, 1 );
}
}
};
/******* NAVBOX GEAR *******/
function Gear( $node ) {
this.$node = $node;
this.$link = this.$node.find( 'a' );
this.href = this.$link.attr( 'href' );
this.renderMenu();
_gears.push( this );
}
Gear.prototype.renderMenu = function () {
var that = this,
collapsible;
this.$node
.addClass( 'nfa__menu mw-collapsed' );
this.$button = $( '<div>' )
.addClass( 'nfa__toggle mw-collapsible-toggle' )
.appendTo( this.$node );
this.$menu = $( '<span>' )
.addClass( 'nfa__dropdown mw-collapsible-content' )
.appendTo( this.$node );
this.$menuList = $( '<ul>' )
.appendTo( this.$menu );
this.renderMenuItem( mw.msg( 'nfa-template-view' ), this.href )
.appendTo( this.$menuList );
this.renderMenuItem( mw.msg( 'nfa-template-settings' ), null, this.openSettingsDialog.bind( this ) )
.appendTo( this.$menuList );
// Prevent default link action
this.$link.parent().appendTo( this.$button );
this.$link.on( 'click', function ( event ) {
event.preventDefault();
} );
// Init collapsible
this.$node.makeCollapsible();
};
Gear.prototype.renderMenuItem = function ( label, href, callback ) {
var li, link, span;
li = $( '<li>' );
link = $( '<a>' )
.attr( 'href', href )
.appendTo( li );
span = $( '<span>' )
.addClass( 'mw-ui-button mw-ui-quiet' )
.text( label )
.appendTo( link );
if ( callback ) {
link.on( 'click', function ( event ) {
event.preventDefault();
callback( event );
} );
}
return li;
}
Gear.prototype.getCollapsible = function() {
return this.$node.data( 'mw-collapsible' );
};
Gear.prototype.showMenu = function () {
var collapsible = this.getCollapsible();
if ( collapsible ) {
collapsible.expand();
}
};
Gear.prototype.hideMenu = function () {
var collapsible = this.getCollapsible();
if ( collapsible ) {
collapsible.collapse();
}
};
Gear.prototype.openSettingsDialog = function () {
if ( !_settingsDialog ) {
_settingsDialog = new SettingsDialogHelper( this );
} else {
_settingsDialog.open();
}
this.hideMenu();
};
Gear.prototype.isInDOM = function () {
return inDOM( this.$node );
};
/******* REDIRECT RESOLVER *******/
function RedirectResolver( pages ) {
this.pages = pages;
this.titles = Object.keys( this.pages );
}
RedirectResolver.prototype.get = function () {
var api = new mw.Api(),
params = {
action: 'query',
titles: this.titles,
redirects: true,
formatversion: 2
};
this.promise = api
.post( params )
.done( this.onDone.bind( this ) );
return this.promise;
};
RedirectResolver.prototype.onDone = function ( data ) {
var that = this;
if ( !data.query || !data.query.redirects ) {
return;
}
$( data.query.redirects ).each( function () {
var item = this,
page = that.pages[item.from];
if ( page ) {
page.resolveRedirect( item.to );
}
} );
};
/******* BADGE REQUEST *******/
function BadgeRequest( titles ) {
this.titles = titles;
}
BadgeRequest.prototype.get = function () {
var api = new mw.ForeignApi( _config.wdAPI ),
params = {
action: 'wbgetentities',
sites: _config.wgDBname,
sitefilter: _config.wgDBname,
titles: this.titles,
props: 'sitelinks',
redirects: 'yes',
formatversion: 2
};
this.promise = api
.post( params )
.done( this.onDone.bind(this) );
return this.promise;
};
BadgeRequest.prototype.onDone = function ( data ) {
if ( !data.entities ) {
return;
}
$.each( data.entities, function ( qid, entity ) {
if ( entity.sitelinks && entity.sitelinks[_config.wgDBname] ) {
var item = entity.sitelinks[_config.wgDBname],
page = _pages[item.title];
if ( page ) {
$( item.badges ).each( function () {
var badge = _config.badges[this];
if ( badge ) {
page.setBadge( badge );
return false;
}
} );
}
}
} );
};
/******* SETTINGS DIALOG ******* */
function SettingsDialog() {
SettingsDialog.parent.call( this );
}
function SettingsDialogHelper( gear ) {
this.gear = gear;
this.isDestroyed = false;
this.isLoaded = false;
this.isOpen = false
this.isOpening = false;
mw.loader.using( [ 'oojs', 'oojs-ui' ], this.load.bind( this ) );
}
SettingsDialogHelper.prototype.load = function () {
var helper = this;
helper.isLoaded = true;
// Configure Setting Dialog
OO.inheritClass( SettingsDialog, OO.ui.ProcessDialog );
SettingsDialog.static.name = 'settingsDialog';
SettingsDialog.static.title = mw.msg( 'nfa-settings-title' );
SettingsDialog.static.actions = [
{
action: 'save',
label: mw.msg( 'nfa-settings-save' ),
flags: [ 'primary', 'progressive' ]
},
{
label: mw.msg( 'nfa-settings-cancel' ),
flags: 'safe'
}
];
SettingsDialog.prototype.initialize = function () {
SettingsDialog.super.prototype.initialize.apply( this, arguments );
// Panel Settings
this.enableOption = new OO.ui.RadioOptionWidget( {
label: mw.msg( 'nfa-settings-enable' )
} );
this.disableOption = new OO.ui.RadioOptionWidget( {
label: mw.msg( 'nfa-settings-disable' )
} );
this.enableSelect = new OO.ui.RadioSelectWidget( {
items: [ this.enableOption, this.disableOption ],
classes: [ 'nfa__enable-select' ]
} );
this.enableSelect.on( 'choose', this.onEnableSelectChoose.bind( this ) );
this.enableSelect.selectItem( _userOptions.enabled ? this.enableOption : this.disableOption );
this.recommendedSelect = new OO.ui.CheckboxInputWidget( {
selected: _userOptions.recommended,
disabled: !_userOptions.enabled
} );
this.recommendedField = new OO.ui.FieldLayout( this.recommendedSelect, {
label: mw.msg( 'nfa-settings-recommended' ),
align: 'inline'
} );
this.goodSelect = new OO.ui.CheckboxInputWidget( {
selected: _userOptions.good,
disabled: !_userOptions.enabled
} );
this.goodField = new OO.ui.FieldLayout( this.goodSelect, {
label: mw.msg( 'nfa-settings-good' ),
align: 'inline'
} );
this.featuredSelect = new OO.ui.CheckboxInputWidget( {
selected: _userOptions.featured,
disabled: !_userOptions.enabled
} );
this.featuredField = new OO.ui.FieldLayout( this.featuredSelect, {
label: mw.msg( 'nfa-settings-featured' ),
align: 'inline'
} );
this.listSelect = new OO.ui.CheckboxInputWidget( {
selected: _userOptions.list,
disabled: !_userOptions.enabled
} );
this.listField = new OO.ui.FieldLayout( this.listSelect, {
label: mw.msg( 'nfa-settings-list' ),
align: 'inline'
} );
this.styleInput = new OO.ui.DropdownInputWidget( {
options: [
{
data: 'default',
label: mw.msg( 'nfa-settings-style-default' )
},
{
data: 'modern',
label: mw.msg( 'nfa-settings-style-modern' )
}
],
value: _userOptions.style,
disabled: !_userOptions.enabled,
classes: [ 'nfa__style-input' ]
} );
this.styleField = new OO.ui.FieldLayout( this.styleInput, {
label: mw.msg( 'nfa-settings-style' ),
align: 'inline'
} );
this.sizeInput = new OO.ui.NumberInputWidget( {
disabled: !_userOptions.enabled,
input: { value: _userOptions.size },
step: 1,
min: _config.badgeSizeMin,
max: _config.badgeSizeMax,
classes: [ 'nfa__size-input' ]
} );
this.sizeField = new OO.ui.FieldLayout( this.sizeInput, {
label: mw.msg( 'nfa-settings-size' ),
align: 'top'
} );
this.fieldsetLayout = new OO.ui.FieldsetLayout();
this.fieldsetLayout.addItems( [
this.featuredField,
this.goodField,
this.recommendedField,
this.listField,
this.styleField,
this.sizeField
] );
this.panelLayout = new OO.ui.PanelLayout( {
padded: true,
expanded: false
} );
this.panelLayout.$element.append(
this.enableSelect.$element,
$( '<hr>' ).addClass( 'nfa__options-form-separator' ),
this.fieldsetLayout.$element
);
this.$body.append( this.panelLayout.$element );
};
SettingsDialog.prototype.onEnableSelectChoose = function ( item ) {
var isDisabled = item === this.disableOption;
this.recommendedSelect.setDisabled( isDisabled );
this.goodSelect.setDisabled( isDisabled );
this.featuredSelect.setDisabled( isDisabled );
this.listSelect.setDisabled( isDisabled );
this.styleInput.setDisabled( isDisabled );
this.sizeInput.setDisabled( isDisabled );
};
SettingsDialog.prototype.getActionProcess = function ( action ) {
var dialog = this;
if ( action === 'save' ) {
return new OO.ui.Process( function () {
return dialog.saveAction();
} );
}
return SettingsDialog.parent.prototype.getActionProcess.call( this, action );
};
SettingsDialog.prototype.saveAction = function () {
var options,
dialog = this;
dialog.pushPending();
options = {
enabled: dialog.enableOption.isSelected(),
recommended: dialog.recommendedSelect.isSelected(),
good: dialog.goodSelect.isSelected(),
featured: dialog.featuredSelect.isSelected(),
list: dialog.listSelect.isSelected(),
style: dialog.styleInput.getValue(),
size: dialog.sizeInput.getValue()
};
return helper.save( options )
.always( function () {
dialog.popPending();
} )
.fail( function () {
dialog.showErrors(
new OO.ui.Error( mw.msg( 'nfa-settings-error' ) )
);
} )
.done( function () {
helper.apply( options );
dialog.close();
} );
};
SettingsDialog.prototype.getBodyHeight = function () {
return this.panelLayout.$element.outerHeight( true );
};
// Configure Windows Manager
if ( !helper.windowManager ) {
helper.windowManager = new OO.ui.WindowManager();
$( document.body ).append( helper.windowManager.$element );
}
helper.open();
};
SettingsDialogHelper.prototype.open = function () {
var that = this;
if( that.isLoaded && !that.isOpen && !that.isOpening ) {
that.isOpening = true;
that.dialog = new SettingsDialog();
that.windowManager.addWindows( [ that.dialog ] );
that.settingsWindow = that.windowManager.openWindow( that.dialog );
that.settingsWindow.opened.then( function () {
that.isOpen = true;
that.isOpening = false;
} );
that.settingsWindow.closed.then( function () {
that.isOpen = false;
that.windowManager.clearWindows();
} );
}
};
SettingsDialogHelper.prototype.close = function () {
this.dialog.close();
};
SettingsDialogHelper.prototype.save = function ( options ) {
options = $.extend( _userOptions, options );
if ( options.size < _config.badgeSizeMin || options.size > _config.badgeSizeMax ) {
options.size = _userOptions.size;
}
var api = new mw.Api(),
params = {
action: 'options',
optionname: _config.optionsName,
optionvalue: JSON.stringify( options )
};
return api.postWithEditToken( api.assertCurrentUser( params ) );
};
SettingsDialogHelper.prototype.apply = function ( options ) {
_userOptions = $.extend( _userOptions, options );
mw.user.options.set( _config.optionsName, JSON.stringify( _userOptions ) );
if ( _userOptions.enabled ) {
processBadges();
} else {
detachBadges();
}
};
/******* MAIN *******/
function garbage() {
// Clear dead gears
_gears = _gears.filter( function( gear ) {
return gear.isInDOM();
} );
}
function prepare() {
var options, title;
// Set interface strings
mw.messages.set( _strings );
// Get user options
try {
options = JSON.parse( mw.user.options.get( _config.optionsName ) );
} catch ( e ) {
console.log( mw.msg( 'nfa-error-user-settings-read', _config.wikilink ) );
}
_userOptions = $.extend( _options, options );
// Normalize badge config
$.each( _config.badges, function ( id, item ) {
// Normalize link url
try {
title = new mw.Title( item.link );
item.url = title.getUrl();
} catch ( e ) {
console.log( mw.msg( 'nfa-error-badge-link-title', _config.wikilink, item.title ) );
}
// Normalize image url
$.each( item.image, function ( name, value ) {
item.image[name] = _config.commonsThumb + value;
} );
} );
// Add body click event to carry dropdown menus
dropdownMenuHelper();
}
function init( $content ) {
var $nodes, $excludeNodes, selector, excludeSelector, $node;
if ( !$content || $content.length === 0 ) {
return;
}
_$context = $content;
_isNavbox = _$context.hasClass( 'navbox' );
// Find gear icons in navboxes
selector = _config.gearSelector.replace( '%navbox%', ( _isNavbox ? '' : _config.navboxSelector ) ).trim();
$nodes = _$context.find( selector );
$nodes.each( function () {
$node = $( this );
new Gear( $node );
} );
// Find links in navboxes
selector = _config.linkSelector.replace( '%navbox%', ( _isNavbox ? '' : _config.navboxSelector ) ).trim();
$nodes = _$context.find( selector );
excludeSelector = _config.linkExcludeSelector.replace( '%navbox%', ( _isNavbox ? '' : _config.navboxSelector ) ).trim();
$excludeNodes = _$context.find( excludeSelector );
$nodes.each( function () {
if ( $.inArray( this, $excludeNodes ) === -1 ) {
$node = $( this );
new Link( $node );
}
} );
if ( _userOptions.enabled ) {
processBadges();
}else {
removeBadges();
}
}
function processBadges() {
var redirects = {},
matchRedirects = false;
// Resolve redirects if exists
$.each( _pages, function ( title, page ) {
if ( page.isRedirect ) {
matchRedirects = true;
redirects[title] = page;
}
} );
if ( matchRedirects ) {
$.when( resolveRedirects( redirects ) ).always( requestBadges );
} else {
requestBadges();
}
}
function resolveRedirects( redirects ) {
var resolver = new RedirectResolver( redirects ),
promise = resolver.get();
return promise;
}
function requestBadges() {
var filtered = {},
matchFiltered = false;
// Request badges if not processed yet
$.each( _pages, function ( title, page ) {
if ( !page.isProcessed && !page.isRedirect ) {
matchFiltered = true
filtered[title] = page;
page.setProcessed( true );
}
} );
if ( matchFiltered ) {
$.when( requestBadgesChains( filtered ) ).always( renderBadges );
} else {
renderBadges();
}
}
function requestBadgesChains( pages ) {
var titles = Object.keys( pages ),
length = titles.length,
count = Math.ceil( length / _config.wdLimit ),
promises = [],
promise;
if ( length > _config.wdLimit ) {
for ( var i = 0; i < count; i++ ) {
var from = i * _config.wdLimit,
to = Math.min( from + _config.wdLimit, length ),
data = titles.slice( from, to );
promises.push( requestBadgesPromise( data ) );
}
promise = $.when.apply($, promises);
} else {
promise = requestBadgesPromise( titles )
}
return promise;
}
function requestBadgesPromise( titles ) {
var request = new BadgeRequest( titles ),
promise = request.get();
return promise;
}
function renderBadges() {
// Execute Order 66 and replace badges with clones
removeBadges();
// Render only pages with badge
$.each( _pages, function ( title, page ) {
if ( page.isProcessed && page.hasBadge ) {
page.renderLinkBadges();
}
} );
}
function removeBadges() {
$.each( _config.badges, function ( id, badge ) {
removeBadgesByType( badge.title );
if ( typeof badge.titleAlias !== 'undefined' ) {
$( badge.titleAlias ).each( function () {
removeBadgesByType( this );
} );
}
} );
}
function removeBadgesByType( title ) {
var $node,
rawRegExp = new RegExp( '%navbox%', 'g'),
regExp = new RegExp( '%title%', 'g'),
rawSelector = _config.badgeSelector.replace( rawRegExp, ( _isNavbox ? '' : _config.navboxSelector ) ).trim(),
selector = rawSelector.replace( regExp, title ),
$nodes = _$context.find( selector );
$nodes.each( function () {
$node = $( this );
if ( _badgeNodes.indexOf( this ) === -1 ) {
$node.remove();
}
} );
}
function detachBadges() {
$( _links ).each( function () {
this.detachBadge();
} );
}
function dropdownMenuHelper() {
var $target, $parents;
document.body.addEventListener( 'click', function ( event ) {
$target = $( event.target );
$parents = $target
.parents( '.nfa__menu' )
.add( $target );
$( _gears ).each( function () {
if ( !$parents.is( this.$node ) ) {
this.hideMenu();
}
} );
}, true );
}
/******* INIT *******/
mw.loader.using( [ 'mediawiki.util', 'mediawiki.ForeignApi', 'jquery.makeCollapsible' ] ).done( function () {
// Prepare config
prepare();
// Then
mw.hook( 'wikipage.editform' ).add( garbage );
mw.hook( 'wikipage.content' ).add( init );
} );
} )();
// </nowiki>