Difference between revisions of "MediaWiki:Common.js"

From Yugipedia
Jump to: navigation, search
m (Oopsie...)
(Add code to create a ToC in card galleries. Spacing.)
Line 9: Line 9:
 
  * this simplifies checking if new code has cleared server caches
 
  * this simplifies checking if new code has cleared server caches
 
  */
 
  */
var LAST_LOG = '14:58, 5 May 2018 (UTC)';
+
var LAST_LOG = '13:49, 22 May 2018 (UTC)';
 
console.log('MediaWiki:Common.js last updated:', LAST_LOG);
 
console.log('MediaWiki:Common.js last updated:', LAST_LOG);
  
Line 461: Line 461:
 
  * Contact [[User talk:Becasita]] if the need arises.
 
  * Contact [[User talk:Becasita]] if the need arises.
 
  */
 
  */
(function($, mw) {
+
( function( window, $, mw ) {
  
 
/**
 
/**
Line 467: Line 467:
 
* Address to «.JS-changed» to find what elements were changed/created.
 
* Address to «.JS-changed» to find what elements were changed/created.
 
*/
 
*/
$(function _specialAskLabelsLinks() {
+
$( function _specialAskLabelsLinks() {
if(mw.config.get('wgPageName').split(/\s*\/\s*/)[0] === 'Special:Ask') {
+
if ( mw.config.get( 'wgPageName' ).split( /\s*\/\s*/ )[ 0 ] === 'Special:Ask' ) {
$('.smwtable').find('th').each(function(i,el) {
+
$( '.smwtable' ).find( 'th' ).each( function( i, el ) {
$(el).html(function() {
+
$( el ).html( function() {
return $(this).text().replace(/\[\[(.*?)]]/g, $('<a>', {
+
return $( this ).text().replace( /\[\[(.*?)]]/g, $( '<a>', {
 
class: 'JS-changed',
 
class: 'JS-changed',
 
href: 'wiki/$1',
 
href: 'wiki/$1',
 
text: '$1'
 
text: '$1'
}).prop('outerHTML'));
+
} ).prop( 'outerHTML' ) );
});
+
} );
});
+
} );
 
}
 
}
});
+
} );
 
/** End. */
 
/** End. */
  
Line 487: Line 487:
 
$(function _fixTabAnchors() {
 
$(function _fixTabAnchors() {
 
// Wait for the tabbers to load:
 
// Wait for the tabbers to load:
mw.loader.using('ext.tabber').then(function() {
+
mw.loader.using( 'ext.tabber' ).then( function() {
  
mw.log('DEBUG: Tabbers loaded!');
+
mw.log( 'DEBUG: Tabbers loaded!' );
$('.tabbernav').each(function(_, el) {
+
$( '.tabbernav' ).each( function( i, el ) {
  
const $el = $(el);
+
const $el = $( el );
 
const $parent = $el.parent();
 
const $parent = $el.parent();
  
 
// Gets the tab content, given a tab label:
 
// Gets the tab content, given a tab label:
const getTab = function($li) {
+
const getTab = function( $li ) {
return $parent.find('.tabbertab').filter(function() {
+
return $parent.find( '.tabbertab' ).filter( function() {
return this.title.trim() === $li.find('a').attr('title').trim();
+
return this.title.trim() === $li.find( 'a' ).attr( 'title' ).trim();
 
});
 
});
 
};
 
};
  
 
// Remove the default click event:
 
// Remove the default click event:
$el.off('click');
+
$el.off( 'click' );
  
 
// Create new click event
 
// Create new click event
$el.children().click(function(e) {
+
$el.children().click( function( e ) {
 
e.preventDefault();
 
e.preventDefault();
  
 
// Current tab:
 
// Current tab:
const $currentLabel = $el.find('.tabberactive');
+
const $currentLabel = $el.find( '.tabberactive' );
const $currentContent = getTab($currentLabel);
+
const $currentContent = getTab( $currentLabel );
  
 
// New tab:
 
// New tab:
const $newLabel = $(this);
+
const $newLabel = $( this );
const $newContent = getTab($newLabel);
+
const $newContent = getTab( $newLabel );
  
 
// Switch tabs:
 
// Switch tabs:
$currentLabel.removeClass('tabberactive');
+
$currentLabel.removeClass( 'tabberactive' );
$newLabel.addClass('tabberactive');
+
$newLabel.addClass( 'tabberactive' );
 
$currentContent.hide();
 
$currentContent.hide();
 
$newContent.show();
 
$newContent.show();
});
+
} );
 +
 
 +
} );
  
});
+
} );
 +
} );
 +
/** End. */
  
});
+
/**
});
+
* Create a ToC for card galleries (using [[Module:Card gallery]]).
 +
*/
 +
$( function _addTocToCardGalleries() {
 +
$( '.mw-headline' ).each( function() {
 +
const sectionName = $( this ).text();
 +
$( '.card-gallery-toc' ).find( 'ul' ).append(
 +
$( '<li>', {
 +
class: 'toc-entry',
 +
html: $( '<a>', {
 +
href: '#' + sectionName.replace( ' ', '_' ),
 +
text: sectionName
 +
} )
 +
} )
 +
);
 +
} );
 +
} );
 
/** End. */
 
/** End. */
  
Line 534: Line 553:
 
  */  
 
  */  
 
$(function _linkEmptyGalleries() {
 
$(function _linkEmptyGalleries() {
const action = mw.util.getParamValue('action');
+
const action = mw.util.getParamValue( 'action' );
const nsNumber = mw.config.get('wgNamespaceNumber');
+
const nsNumber = mw.config.get( 'wgNamespaceNumber' );
  
 
// Function to link the empty galleries to the upload page:
 
// Function to link the empty galleries to the upload page:
 
const linkEmptyGalleries = function() {
 
const linkEmptyGalleries = function() {
$('.thumb').each(function() {
+
$( '.thumb' ).each( function() {
const $this = $(this);
+
const $this = $( this );
if(!$this.children().length) {
+
if ( !$this.children().length ) {
 
// Is an empty gallery box.
 
// Is an empty gallery box.
 
const text = $this.text();
 
const text = $this.text();
$this.text('');
+
$this.text( '' );
 
$this.append(
 
$this.append(
$('<a>', {
+
$( '<a>', {
 
class: 'noFile',
 
class: 'noFile',
 
href: '/index.php?title=Special:Upload&wpDestFile=' + text,
 
href: '/index.php?title=Special:Upload&wpDestFile=' + text,
 
text: text
 
text: text
})
+
} )
 
);
 
);
 
}
 
}
});
+
} );
 
};
 
};
  
Line 560: Line 579:
  
 
// Check if there were changes in the DOM to keep the links alive (when previewing edits, etc.):
 
// Check if there were changes in the DOM to keep the links alive (when previewing edits, etc.):
if(window.MutationObserver && ['edit', 'submit'].includes(action)) {
+
if ( window.MutationObserver && [ 'edit', 'submit' ].includes( action ) ) {
  
 
// Wait for the editor to load:
 
// Wait for the editor to load:
mw.loader.using('jquery.wikiEditor').then(function() {
+
mw.loader.using( 'jquery.wikiEditor' ).then( function() {
  
 
// (jQuery) Node to observe:
 
// (jQuery) Node to observe:
const $targetNode = $('.wikiEditor-ui-view-preview').find('.wikiEditor-preview-contents');
+
const $targetNode = $( '.wikiEditor-ui-view-preview' ).find( '.wikiEditor-preview-contents' );
  
 
// Options for the observer (which mutations to observe).
 
// Options for the observer (which mutations to observe).
Line 577: Line 596:
  
 
// Create an observer instance and observe:
 
// Create an observer instance and observe:
new MutationObserver(function(mutationsList) {
+
new MutationObserver( function( mutationsList ) {
 
// No need to iterate over mutationList,
 
// No need to iterate over mutationList,
 
// since we just want to execute the following function once.
 
// since we just want to execute the following function once.
 
//console.log('Linking...');  
 
//console.log('Linking...');  
 
linkEmptyGalleries();
 
linkEmptyGalleries();
}).observe($targetNode.get(0), options);
+
} ).observe( $targetNode.get( 0 ), options );
 
 
});
+
} );
  
 
}
 
}
});
+
} );
 
/** End. */
 
/** End. */
  
})(window.jQuery, window.mediaWiki);
+
} )( window, window.jQuery, window.mediaWiki );
  
 
/* End of mw.loader.using callback; DO NOT ADD CODE BELOW THIS LINE */
 
/* End of mw.loader.using callback; DO NOT ADD CODE BELOW THIS LINE */
 
});
 
});

Revision as of 13:49, 22 May 2018

/*global mw, $, console, enableOldForumEdit */
/*jshint browser:true, curly:false, eqnull:true, strict:false */
mw.loader.using(['mediawiki.util', 'jquery.client'], function () {
/* Begin of mw.loader.using callback */


/**
 * update this (replace the timestamp with 5 tildes) whenever this page is edited
 * this simplifies checking if new code has cleared server caches
 */
var LAST_LOG = '13:49, 22 May 2018 (UTC)';
console.log('MediaWiki:Common.js last updated:', LAST_LOG);


/**
 * dev:LastEdited customization
 * see [[w:c:dev:LastEdited#Customization]] for documentation/more options
 */
window.lastEdited = {
	namespaces: { /* [[User:Dinoguy1000/namespaces]] has a full list */
		include: [ 102, 103,	/* Property (SMW) */
				   106, 107,	/* Form (SMW) */
				   108, 109,	/* Concept (SMW) */
				   170, 171,	/* Filter */
				   3000, 3001,	/* Portal */
				   3004, 3005,	/* Gallery */
				   3006, 3007,	/* Set List */
				   3008, 3009,	/* Rulings */
				   3010, 3011,	/* Errata */
				   3012, 3013,	/* Artworks */
				   3014, 3015,	/* Tips */
				   3016, 3017,	/* Trivia */
				   3018, 3019,	/* Appearances */
				   3020, 3021,	/* Names */
				   3022, 3023,	/* Lores */
				   3024, 3025,	/* Set Gallery */ ]
	}
};

/**
 * Load Dev scripts and whatnot
 * at [[MediaWiki:ImportJS]]
 */

/**
 * Collapsible tables
 *
 * Allows tables to be collapsed, showing only the header. See [[Help:Collapsing]].
 *
 * @version 2.0.3 (2014-03-14)
 * @source https://www.mediawiki.org/wiki/MediaWiki:Gadget-collapsibleTables.js
 * @author [[User:R. Koot]]
 * @author [[User:Krinkle]]
 */

var autoCollapse = 2,
	collapseCaption = 'hide',
	expandCaption = 'show',
	tableIndex = 0;

function collapseTable( tableIndex ) {
	var Button = document.getElementById( 'collapseButton' + tableIndex ),
		Table = document.getElementById( 'collapsibleTable' + tableIndex );

	if ( !Table || !Button ) {
		return false;
	}

	var Rows = Table.rows,
		i,
		$row0 = $(Rows[0]);

	if ( Button.firstChild.data === collapseCaption ) {
		for ( i = 1; i < Rows.length; i++ ) {
			Rows[i].style.display = 'none';
		}
		Button.firstChild.data = expandCaption;
	} else {
		for ( i = 1; i < Rows.length; i++ ) {
			Rows[i].style.display = $row0.css( 'display' );
		}
		Button.firstChild.data = collapseCaption;
	}
}

function createClickHandler( tableIndex ) {
	return function ( e ) {
		e.preventDefault();
		collapseTable( tableIndex );
	};
}

function createCollapseButtons( $content ) {
	var NavigationBoxes = {},
		$Tables = $content.find( 'table' ),
		i;

	$Tables.each( function( i, table ) {
		if ( $(table).hasClass( 'collapsible' ) ) {

			/* only add button and increment count if there is a header row to work with */
			var HeaderRow = table.getElementsByTagName( 'tr' )[0];
			if ( !HeaderRow ) {
				return;
			}
			var Header = table.getElementsByTagName( 'th' )[0];
			if ( !Header ) {
				return;
			}

			NavigationBoxes[ tableIndex ] = table;
			table.setAttribute( 'id', 'collapsibleTable' + tableIndex );

			var Button     = document.createElement( 'span' ),
				ButtonLink = document.createElement( 'a' ),
				ButtonText = document.createTextNode( collapseCaption );
			// Styles are declared in [[MediaWiki:Common.css]]
			Button.className = 'collapseButton';

			ButtonLink.style.color = Header.style.color;
			ButtonLink.setAttribute( 'id', 'collapseButton' + tableIndex );
			ButtonLink.setAttribute( 'href', '#' );
			$( ButtonLink ).on( 'click', createClickHandler( tableIndex ) );
			ButtonLink.appendChild( ButtonText );

			Button.appendChild( document.createTextNode( '[' ) );
			Button.appendChild( ButtonLink );
			Button.appendChild( document.createTextNode( ']' ) );

			Header.insertBefore( Button, Header.firstChild );
			tableIndex++;
		}
	} );

	for ( i = 0;  i < tableIndex; i++ ) {
		if ( $( NavigationBoxes[i] ).hasClass( 'collapsed' ) ||
			( tableIndex >= autoCollapse && $( NavigationBoxes[i] ).hasClass( 'autocollapse' ) )
		) {
			collapseTable( i );
		}
		else if ( $( NavigationBoxes[i] ).hasClass ( 'innercollapse' ) ) {
			var element = NavigationBoxes[i];
			while ((element = element.parentNode)) {
				if ( $( element ).hasClass( 'outercollapse' ) ) {
					collapseTable ( i );
					break;
				}
			}
		}
	}
}

mw.hook( 'wikipage.content' ).add( createCollapseButtons );
/*** end copied from [[wikipedia:MediaWiki:Common.js]] ***/


/**
 * Archive edit tab/button disabling
 *
 * Disables the edit tab/button on discussion pages to stop people bumping old forum threads or editing archive pages.
 * Page can still be edited by going via the edit tab on the history etc, or by
 * typing the edit address manually.
 * By [[User:Spang|Spang]]
 * Wikia (Oasis) support by [[User:Uberfuzzy|Uberfuzzy]]
 */

function disableEditLink() {
	var ns = mw.config.get('wgNamespaceNumber'),
		skin = mw.config.get('skin');
	if (ns !== 110 && ns !== 2 && ns % 2 !== 1) { return; }
	if (
		(skin !== 'vector' && skin !== 'monobook') || // need to look into MinervaNeue
		$.inArray('sysop', mw.config.get('wgUserGroups')) > -1 || // disable completely for admins
		typeof enableOldForumEdit !== 'undefined' ||
		!$('#archived-edit-link')[0]
	) { return; }

	var editLink = $('#ca-edit a');
	if (!editLink[0]) { return; }

	editLink.html('Archived').removeAttr('href').removeAttr('title').css({'color':'gray','cursor':'auto'});

	$('span.editsection-upper').remove();
}
$(disableEditLink);

/**
 * Cleanup excessive space in hlist elements
 */
var items = document.querySelectorAll('.hlist li, .hlist dt, .hlist dd');
for (var i = items.length - 1; i >= 0; i--) {
	items[i].innerHTML = items[i].innerHTML.trim();
}

/**
 * Page format checking
 *
 * Maintainers: [[User:Falzar FZ]]
 */
var mNamespace       = mw.config.get('wgCanonicalNamespace'),
	mNamespaceNumber = mw.config.get('wgNamespaceNumber'),
	mAction          = mw.util.getParamValue('action'),
	mSection         = mw.util.getParamValue('section');

	/*
	 * Check that you have signed your post on Talk pages and Forum pages.

	 * Disable for yourself on every page by adding:
				var signCheck = 'Disable';
	   to [[Special:MyPage/common.js]]

	 * Alternatively, if you sign with 3 tildes, add:
			var signCheck = 3;

	 * To disable checking on a specific page for everyone, add:
			<!--~~~~-->
	   to that page somewhere, it will overlook it each time.
	 */
if (mNamespaceNumber % 2 === 1 || mNamespaceNumber === 110) {
	if (!document.URL.match('&undo') && !document.URL.match('/Archive')) {
		$(function() {
			$('#wpSave, #wpPreview').mousedown(signChecker);
		});

		var vSignCheckerCounter = 0,
			mInitialLength = $('#wpTextbox1').val().length;
		function signChecker() {
			var vTildes = '~~\~~',
			// Bypassing the line in the forum template.
				vForumMessage = 'Be sure to sign your edits with four tildes: ' + vTildes,
				vNoWiki = '<nowiki>' + vTildes + '</nowiki>',
				vMinorChecked = $('#wpMinoredit').is(':checked'),
				mFinalLength = $('#wpTextbox1').val().length,

				vText = $('#wpTextbox1').val().replace(vForumMessage, '').replace(vNoWiki, '');
			if (vSignCheckerCounter < 3 && !vText.match(vTildes) &&
					!vText.match('{\{[Tt]alk ?header}}') && !vText.match('{\{[Dd]elete') &&
					!vMinorChecked && !$('#wpSummary').val().match(/move/i) &&
					!$('#wpSummary').val().match(/archive/i) &&
					mFinalLength > mInitialLength + 15) {
				vSignCheckerCounter++;
				if (!window.signCheck) {
					alert('Please sign your post by adding 4 tildes (' + vTildes + ') to the end of your post.');
				} else if (window.signCheck === 3) {
					alert('Please sign your post by adding 3 tildes (~\~~) to the end of your post.');
				} else if (window.signCheck === 'Disable') {
					vSignCheckerCounter = 9;
				}
			}
		}
	}
}

/**
 * Add Template:Navigation if it's not there.
 */
if (
	(mNamespace === 'Card_Rulings' && $('#wpTextbox1').val().indexOf('[\[Category:Group Rulings') === -1) ||
	['Gallery', 'Errata', 'Tips', 'Appearances', 'Trivia', 'Lores', 'Artworks', 'Names', 'Sets']
		.indexOf(mNamespace.replace('Card_', '')) !== -1
) {
	if (!mSection && mAction !== 'submit' && typeof $('#wpTextbox1').val() !== 'undefined') {
		$(addNav);

		function addNav() {
			var vText = $('#wpTextbox1').val()
				.replace('{\{navigation', '{\{Navigation')
				.replace('{\{Navigation2}', '{\{Navigation|mode=nonGame}');
			if (!vText.match('{\{Navigation') && !vText.match('{\{Delete')) {
				$('#wpTextbox1').val('{\{Navigation}}\n\n' + vText);
			} else {
				$('#wpTextbox1').val(vText);
			}

			$('form[name=editform]').submit(function() {
				if ($('#wpTextbox1').val() === '{\{Navigation}}\n\n') {
					alert('You have not made any changes to the template.');
					return false;
				}
			});
		}
	}
}

/**
 * Add Template:Talkheader if it's not there.
 */
if (mNamespaceNumber % 2 === 1 && mNamespaceNumber !== 3 && !mSection && mAction !== 'submit') {
	$(addTalkheader);

	function addTalkheader() {
		var vText = $('#wpTextbox1').val().replace(/{\{[Tt]alkheader/, '{\{Talk header');
		if (!vText.match('{\{Talk header') && !vText.match('{\{Delete')) {
			$('#wpTextbox1').val('{\{Talk header}}\n\n' + vText);
		} else {
			$('#wpTextbox1').val(vText);
		}
	}
}

/**
 * Add a preload depending on the namespace during page creation from redlink.
 */
if (mw.util.getParamValue('redlink')) {
	var vPreloadText = '';
	switch (mNamespace) {
		case 'Card_Tips': // fallthrough
		case 'Card_Trivia': // fallthrough
		case 'Card_Names':
			vPreloadText += '* '; // Deliberate no "\n" at the end.
			break;
		case 'Card_Gallery':
			vPreloadText += '{\{GalleryHeader|lang=en}}\n<gallery widths="175px">\n' +
				'Image.png  | [[Card Number]] ([[Rarity]])<br />\'\'([[Edition]])\'\'<br />[[Set Name]]\n</gallery>\n|}\n\n' +
				'{\{GalleryHeader|lang=jp|set=Anime}}\n<gallery widths="175px">\nImage.png  | [[]]\n</gallery>\n|}\n';
			break;
		case 'Card_Appearances':
			vPreloadText += '* In [[Yu-Gi-Oh! VRAINS - Episode 000|episode 00]], [[character name]] plays this card ' +
				'against [[opponent name]].\n';
			break;
		case 'Card_Errata':
			vPreloadText += '{\{Errata table\n| lore0  = \n| image0 = \n| cap0   = [[Card Number]]<br />' +
				'[[Set Name]]\n\n| lore1  = \n| image1 = \n| cap1   = [[Card Number]]<br />[[Set Name]]\n}}\n';
			break;
		case 'Card_Artworks':
			vPreloadText += '* \n\n{\{ArtworkHeader|lang=jp}}\n<gallery widths="275px">\n' +
				'Image.png  | Japanese\nImage.png  | International\n</gallery>\n|}\n';
			break;
	}
	if (vPreloadText !== '') {
		$(addPreload('{\{Navigation}}\n\n' + vPreloadText));
	}

	function addPreload(pBlankTemplate) {
		$('#wpTextbox1').val(pBlankTemplate);

		$('#wpSave, #wpPreview').mousedown(cleanUpStuff);
		function cleanUpStuff() {
			$('#wpTextbox1').val($('#wpTextbox1').val()
				.replace('{\{Navigation2}}', '{\{Navigation|mode=nonGame}}')
				.replace('{\{Navigation3}}', '{\{Navigation|mode=otherGame}}')
			);
		}

		$('form[name=editform]').submit(function() {
			if ($('#wpTextbox1').val() === pBlankTemplate) {
				alert('You have not made any changes to the template.');
				return false;
			}
		});
	}

}

/**
 * Add missing preload to [[MediaWiki:Createbox-exists]].
 * Using js since there doesn't seem to be a "getURL" option in the wikia magic words.
 */
if (mAction === 'create' && $('[name="preload"]').val() === '') {
	$('[name="preload"]').val(mw.util.getParamValue('preload'));
}

/**
 * Remove empty rows from {{Infobox}} transclusions
 */
$('.infobox tr').each(function () {
	if (
		!$.trim($(this).text()) &&
		!$(this).find('img').length &&
		!$(this).find('hr').length
	) {
		$(this).remove();
	}
});

/**
 * Allow for redirecting Luster_Dragon#2 to Luster_Dragon_2 etc. via {{Hash redirect}}
 */
if ($('.hash_redirect')) {
	var redirects = document.getElementsByClassName('hash_redirect');
	var hash = window.location.hash.substring(1);

	for (var k = 0; k < redirects.length; k++) {
		if (redirects[k].getAttribute('data-value') === hash) {
			window.location = window.location.href.replace('#', '_');
		}
	}
}

/**
 * Show card details on hover
 */
$('.card-link').on('mouseenter', function() {
	if (! document.getElementById('main-card-table')) {
		$(this).find('.card-link-hover-data').load(
			this.getElementsByTagName('a')[0].href + ' #main-card-table', function() {
				$(this).find('.chronology').remove();
			}
		);
	}
});
$('.card-link').on('mouseleave', function() {
	$('.card-link-hover-data').html('');
});

/**
 * Image switcher for card tables
 */
$('.image-switcher a').on('click', function(ev) {
	ev.preventDefault();

	var $imagecolumn   = $(this).parents('.imagecolumn'),
		$selected      = $(this).parents('.image-dimensions'),
		$image_wrapper = $imagecolumn.find('.cardtable-main_image-wrapper'),
		$main_image    = $image_wrapper.find('img:first'),
		image_name     = this.getAttribute('title'),

	// Images are not to go wider than the first one.
		max_width    = $imagecolumn.data('max_width') ? $imagecolumn.data('max_width') : $main_image.width(),
	// Natural dimensions of the selected image
		n_width      = $selected.data('width'),
		n_height     = $selected.data('height'),
	// Dimensions to display the selected image at
		width        = (n_width < max_width) ? n_width  : max_width,
		height       = (n_width < max_width) ? n_height : n_height * width / n_width,

		src = this.href;
		/*srcset = [1.5, 2].map(function(ratio) {
			return src.replace('\.com//', '$&thumb/') + '/' + Math.round(width * ratio) + 'px-' + image_name + ' ' + ratio + 'x';
		}).join();*/
	if (width !== n_width) {
		src = '/thumb.php?f=' + image_name + '&w=' + width;
	}

	// Preventing content jumping 
	$imagecolumn.css('width', max_width);
	$imagecolumn.find('\+.infocolumn').css('width', 'calc(100% - '+max_width+'px)');
	$image_wrapper.css('min-height', $image_wrapper.height());

	var img = new Image();
	img.onload = function() {
		// Change the main image's URL to the new image and set its width and height 
		$main_image
			.attr('src', src)
			//.attr('srcset', srcset)
			.attr('width', width)
			.attr('height', height)
			.removeAttr('srcset');

		// Change the main image's link and hover text to match the new image
		$main_image.parents('a')
			.attr('href', '/wiki/File:'+image_name)
			.attr('title', image_name);
	};
	img.src = src;
});


/**
 * The following code is currently maintained by [[User:Becasita]].
 * Contact [[User talk:Becasita]] if the need arises.
 */
( function( window, $, mw ) {

	/**
	 * Fix Special:Ask table headers when wikilinked.
	 * Address to «.JS-changed» to find what elements were changed/created.
	 */
	$( function _specialAskLabelsLinks() {
		if ( mw.config.get( 'wgPageName' ).split( /\s*\/\s*/ )[ 0 ] === 'Special:Ask' ) {
			$( '.smwtable' ).find( 'th' ).each( function( i, el ) {
				$( el ).html( function() {
					return $( this ).text().replace( /\[\[(.*?)]]/g, $( '<a>', {
						class: 'JS-changed',
						href: 'wiki/$1',
						text: '$1'
					} ).prop( 'outerHTML' ) );
				} );
			} );
		}
	} );
	/** End. */

	/**
	 * Fix tabbers labels achors.
	 */
	$(function _fixTabAnchors() {
		// Wait for the tabbers to load:
		mw.loader.using( 'ext.tabber' ).then( function() {

			mw.log( 'DEBUG: Tabbers loaded!' );
			$( '.tabbernav' ).each( function( i, el ) {

				const $el = $( el );
				const $parent = $el.parent();

				// Gets the tab content, given a tab label:
				const getTab = function( $li ) {
					return $parent.find( '.tabbertab' ).filter( function() {
						return this.title.trim() === $li.find( 'a' ).attr( 'title' ).trim();
					});
				};

				// Remove the default click event:
				$el.off( 'click' );

				// Create new click event
				$el.children().click( function( e ) {
					e.preventDefault();

					// Current tab:
					const $currentLabel = $el.find( '.tabberactive' );
					const $currentContent = getTab( $currentLabel );

					// New tab:
					const $newLabel = $( this );
					const $newContent = getTab( $newLabel );

					// Switch tabs:
					$currentLabel.removeClass( 'tabberactive' );
					$newLabel.addClass( 'tabberactive' );
					$currentContent.hide();
					$newContent.show();
				} );

			} );

		} );
	} );
	/** End. */

	/**
	 * Create a ToC for card galleries (using [[Module:Card gallery]]).
	 */ 
	$( function _addTocToCardGalleries() {
		$( '.mw-headline' ).each( function() {
			const sectionName = $( this ).text();
			$( '.card-gallery-toc' ).find( 'ul' ).append(
				$( '<li>', {
					class: 'toc-entry',
					html: $( '<a>', {
						href: '#' + sectionName.replace( ' ', '_' ),
						text: sectionName
					} )
				} )
			);
		} );
	} );
	/** End. */

 	/**
 	 * Links for image uploads on galleries.
 	 */ 
	$(function _linkEmptyGalleries() {
		const action = mw.util.getParamValue( 'action' );
		const nsNumber = mw.config.get( 'wgNamespaceNumber' );

		// Function to link the empty galleries to the upload page:
		const linkEmptyGalleries = function() {
			$( '.thumb' ).each( function() {
				const $this = $( this );
				if ( !$this.children().length ) {
					// Is an empty gallery box.
					const text = $this.text();
					$this.text( '' );
					$this.append(
						$( '<a>', {
							class: 'noFile',
							href: '/index.php?title=Special:Upload&wpDestFile=' + text,
							text: text
						} )
					);
				}
			} );
		};

		// Execute it:
		linkEmptyGalleries();

		// Check if there were changes in the DOM to keep the links alive (when previewing edits, etc.):
		if ( window.MutationObserver && [ 'edit', 'submit' ].includes( action ) ) {

			// Wait for the editor to load:
			mw.loader.using( 'jquery.wikiEditor' ).then( function() {

				// (jQuery) Node to observe:
				const $targetNode = $( '.wikiEditor-ui-view-preview' ).find( '.wikiEditor-preview-contents' );

				// Options for the observer (which mutations to observe).
				// We only want to see when content is loaded from the backed
				// and then appended.
				// Therefore, observe when new child nodes are placed or removed:
				const options = {
					childList: true
				};

				// Create an observer instance and observe:
				new MutationObserver( function( mutationsList ) {
					// No need to iterate over mutationList,
					// since we just want to execute the following function once.
					//console.log('Linking...'); 
					linkEmptyGalleries();
				} ).observe( $targetNode.get( 0 ), options );
				
			} );

		}
	} );
	/** End. */

} )( window, window.jQuery, window.mediaWiki );

/* End of mw.loader.using callback; DO NOT ADD CODE BELOW THIS LINE */
});