MediaWiki:Common.js

/* Any JavaScript here will be loaded for all users on every page load. */

/** * Instead of cluttering up the global scope with * variables, they should instead be set as an * object of this global variable * * E.g: Instead of *  window.myVar = 'blah'; * use *  window.mcw.myVar = 'blah'; */ window.mcw = {};

/** * Location of baseURL and wikiURL * * baseURL is where the wiki is actually installed * It can be seen in URLs such as index.php and api.php * It's usually /w/ * * wikiURL is the alias for baseURL + index.php?title= * It can be seen when viewing any normal wiki page * It's usually /wiki/ */ window.mcw.baseURL = '/'; window.mcw.wikiURL = '/wiki/';

/** * Extra toolbar options * * Description: Adds extra buttons to the editing toolbar. * Due to the way this works, it has to be loaded before the * toolbar loads (so it can't be in the onload function). *  * Maintainers: wikipedia:User:MarkS, wikipedia:User:Voice of All, wikipedia:User:R. Koot */ ( function { 'use strict';	var buttons = ;	$.each( buttons, function { mwCustomEditButtons.push( this ); } ); } );

$( function { 'use strict';

/** * Collapsible tables * * Based on http://www.mediawiki.org/wiki/Manual:Collapsible_tables#Common.js_script_.28before_1.18.29 * * @maintainers User:Ultradude25 */ var collapseText = 'hide', expandText = 'show'; window.mcw.makeCollapsible = function { var $tables = $( 'table.collapsible' ); if ( $tables.length ) { var collapseButton, buttonText = ' [ ' + collapseText + ' ] '; $tables.each( function {			var $table = $( this ), header;			if ( $table.hasClass( 'made-collapsible' ) ) {				return true;			}			if ( $table.find( '.collapse-button' ).length ) {				header = $table.find( 'tr:first .collapse-button' );			} else {				header = $table.find( 'tr:first th:first' );			}			if ( !header.length || !$table.find( 'tr' ).not( 'tr:first' ).text.replace( /\n/g, '' ).length ) {				return true;			}			if ( $table.hasClass( 'collapse-button-none' ) ) {				header.append( buttonText );			} else {				header.prepend( buttonText );			}			collapseButton = $table.find( '.collapsible-button .jslink' );			if ( $table.hasClass( 'collapsed' ) ) {				collapseButton.text( expandText );			}			$table.addClass( 'made-collapsible' );		} ); } };

$( '#content' ).delegate( 'table.collapsible .collapsible-button .jslink', 'click', function( e ) {	var $table = $( this ).closest( 'table.collapsible' );	// Stop table sorting activating when clicking the link	e.stopPropagation;	if ( $table.hasClass( 'collapsed' ) ) {		$table.removeClass( 'collapsed' ).addClass( 'expanded' );		$( this ).text( collapseText );	} else {		$table.removeClass( 'expanded' ).addClass( 'collapsed' );		$( this ).text( expandText );	} } ); window.mcw.makeCollapsible;

/** * Fix edit summary prompt for undo * * Fixes the fact that the undo function combined with the "no edit summary prompter" * causes problems if leaving the edit summary unchanged. * Added by wikipedia:User:Deskana, code by wikipedia:User:Tra. * See https://bugzilla.wikimedia.org/show_bug.cgi?id=8912 */ if ( document.location.search.indexOf( "undo=" ) !== -1 && document.getElementsByName( 'wpAutoSummary' )[0] ) { document.getElementsByName( 'wpAutoSummary' )[0].value='1'; }

window.mcw.animation = function { /**	 * Element animator *	 * Will cycle the active class on any child elements * within an element with the animated class. */	if ( window.mcw.animate === undefined && $( '.animated' ).length ) { window.mcw.animate = setInterval( function {			$( '.animated' ).each( function { var current = $( this ).find( '.active' ).removeClass( 'active' ), next = current.next; if ( !current.next.length ) { next = $( this ).children.eq( 0 ); }				next.addClass( 'active' ); } );		}, 2000 );	}	/**	 * Frame loader * 	 * Loads a semi-colon separated list of images * to be animated by the element animator * 	 * Has special support for Template:Grid */	var $animate = $( '.animated' ), size = {}; if ( $animate.length ) { $animate.each( function {			var imgs = $( this ).data( 'imgs' ), imgSize = $( this ).data( 'img-size' ),				grid = $( this ).closest( '.grid' ), mod = $( this ).data( 'mod' );			if ( !imgs ) {				return true;			}			if ( grid.length ) {				grid = true;				imgSize = '32x32';			} else {				grid = false;				if ( imgSize ) {					imgSize = imgSize.split( 'x' );					imgSize[0] = imgSize[0].replace( /[\D ]/,  );					imgSize[1] = imgSize[1].replace( /[\D ]/,  );					if ( imgSize[1] ) {						imgSize[0] += 'x' + imgSize[1];					}					imgSize = imgSize[0];				} else {					imgSize = '';				}			}			if ( size[imgSize] === undefined ) {				size[imgSize] = [];			}			imgs = imgs.split( ';' );			imgs.shift;			$.each( imgs, function { if ( !this.trim ) { return true; }				var parts, name; if ( grid ) { if ( this.indexOf( ':' ) > -1 ) { parts = $.map( this.split( /[:,]+/ ), $.trim ); if ( parts[0].toLowerCase === 'v' || parts[0].toLowerCase === 'vanilla' ) { name = 'File:Grid ' + parts[1] + '.png'; } else { name = 'File:Grid ' + parts[1] + ' (' + parts[0] + ').png'; }					} else { parts = $.map( this.split( ',' ), $.trim ); if ( !mod ) { name = 'File:Grid ' + parts[0] + '.png'; } else { name = 'File:Grid ' + parts[0] + ' (' + mod + ').png'; }					}					if ( size[imgSize].indexOf( name ) < 0 ) { size[imgSize].push( name ); }				} else if ( size[imgSize].indexOf( 'File:' + this.trim ) < 0 ) { size[imgSize].push( 'File:' + this.trim ); }			} );		} );		var redirectPromise = [], urlPromise = [], redirects = {}, urls = {}; $.each( size, function( size ) {			var titles = this;			if ( !titles ) {				return true;			}			// Split titles up into blocks of 50, which is the API's title limit for standard users			for ( var i = 0; i < titles.length; i += 50 ) {				var section = titles.slice( i, i + 50 ).join( '|' );				redirectPromise.push( // Thanks to bug 23750 (https://bugzilla.wikimedia.org/show_bug.cgi?id=23750) // &redirects doesn't work properly with prop=imageinfo. Some of the images // will return without any imageinfo, even though they are valid. // So the redirects have to be resolved in a separate request... $.ajax( {						type: 'POST',						url: window.mcw.baseURL + 'api.php?action=query&format=json&redirects',						data: { titles: section },						timeout: 20000					} ).done( function( data ) {						if ( data.query.redirects ) {							$.each( data.query.redirects, function { redirects[this.to] = this.from; section = section.replace( this.from, this.to ); } );						}						var thumburl = '', sizes = size.split( 'x' );						if ( sizes[0] ) {							thumburl = '&iiurlwidth=' + sizes[0];							if ( sizes[1] ) {								thumburl += '&iiurlheight=' + sizes[1];							}						}						urlPromise.push( $.ajax( {								type: 'POST',								url: window.mcw.baseURL + 'api.php?action=query&format=json&prop=imageinfo&iiprop=url' + thumburl,								data: { titles: section },								timeout: 20000							} ).done( function( data ) {								$.each( data.query.pages, function( index ) { if ( index < 0 ) { return true; }									if ( !this.imageinfo ) { console.error( 'Imageinfo is empty' ); return true; }									var url = this.imageinfo[0].thumburl || this.imageinfo[0].url; if ( redirects.hasOwnProperty( this.title ) ) { urls = url; } else { urls = url; }								} );							} ).fail( function( error ) {								console.error( error );							} ) );					} ).fail( function( error ) {						console.error( error );					} ) );			}		} );		$.when.apply( $, redirectPromise ).then( function {			$.when.apply( $, urlPromise ).then( function { $animate.each( function {					var imgs = $( this ).data( 'imgs' ), imgSize = $( this ).data( 'img-size' ), html = ,						grid = $( this ).closest( '.grid' ), mod = $( this ).data( 'mod' );					if ( !imgs ) {						return true;					}					if ( grid.length ) {						grid = true;						imgSize = '32x32';					} else {						grid = false;						if ( imgSize ) {							imgSize = imgSize.split( 'x' );							imgSize[0] = imgSize[0].replace( /[\D ]/,  );							imgSize[1] = imgSize[1].replace( /[\D ]/,  );							if ( imgSize[1] ) {								imgSize[0] += 'x' + imgSize[1];							}							imgSize = imgSize[0];						} else {							imgSize = ;						}					}					imgs = imgs.split( ';' );					imgs.shift;					$.each( imgs, function { if ( !this.trim ) { if ( grid ) { html += ' '; }							return true; }						var parts, name, link, url, num; if ( grid ) { if ( this.indexOf( ':' ) > -1 ) { parts = $.map( this.split( /[:,]+/ ), $.trim ); if ( parts[0].toLowerCase === 'v' || parts[0].toLowerCase === 'vanilla' ) { name = link = parts[1]; url = urls['Grid ' + parts[0] + '.png' + imgSize]; num = parts[2]; } else { name = parts[1] + ' (' + parts[0] + ')'; link = 'Mods/' + parts[0] + '/' + parts[1]; url = urls['Grid ' + name + '.png' + imgSize]; num = parts[2]; }							} else { parts = $.map( this.split( ',' ), $.trim ); if ( !mod ) { name = link = parts[0]; url = urls['Grid ' + parts[0] + '.png' + imgSize]; num = parts[1]; } else { name = parts[0] + ' (' + mod + ')'; link = 'Mods/' + mod + '/' + parts[0]; url = urls['Grid ' + name + '.png' + imgSize]; num = parts[1]; }							}							html += ' '; if ( name ) { if ( url ) { html += ''; if ( num ) { html += ' ' + num + ' '; }								} else { html += ''; }							} else { html += ' '; }							html += ' '; } else { name = this.trim; html += ' '; if ( urls[name + imgSize] ) { html += ''; } else { html += 'File:' + name + ''; }							html += ' '; }					} );					$( this ).append( html ).data( 'imgs', null );				} ); } );		} );	} }; window.mcw.animation;

/** * Pause grid GUI templates (e.g. Template:Grid/Crafting Table) on mouseover * * This is so people have a chance to look at each image on the cell * and click on pages they want to view. */ $( '#content' ).delegate( '.grid-Crafting_Table, .grid-furnace, .grid-Brewing_Stand', {	'mouseenter': function { 		$( this ).find( '.animated' ).removeClass( 'animated' ).addClass( 'paused' );	},	'mouseleave': function {		$( this ).find( '.paused' ).removeClass( 'paused' ).addClass( 'animated' );	} } );

/** * Add fake last-child class in navboxes for IE8 */ if ( $.client.profile.name === 'msie' && $.client.profile.versionBase === '8' ) { $( '.navbox-list li:last' ).addClass( 'last-child' ); }

/** * Page loader * * Allows a page to be downloaded and shown within another page. * Use with Template:LoadPage */ var loadText = 'load', showText = 'show', hideText = 'hide';

$( '.load-page' ).find( '.mw-headline:first' ).append( ' [ ' + loadText + ' ] ' );

$( '.load-page-button > .jslink' ).live( 'click', function {	var $this = $( this ), $body = $this.closest( '.load-page' ), $content = $body.find( '.load-page-content' );	if ( $body.hasClass( 'loading' ) ) {		return;	}	if ( $this.text === loadText ) {		$body.addClass( 'loading' );		$( 'body' ).css( 'cursor', 'progress' );		$.ajax( { url: window.mcw.baseURL + 'api.php?format=json&action=parse&prop=text&redirects=1&page=' + mw.util.wikiUrlencode( $body.data( 'page' ) ), dataType: 'json', timeout: 20000 } ).done( function( data ) { if ( data.error ) { if ( $( '#error-dialog' ).length ) { return; }				mw.loader.using( 'jquery.ui.dialog', function {					$body.removeClass( 'loading' );					$( 'body' ).css( 'cursor', 'auto' );					$( '#netbar' ).after( ' ' );					$( '#error-dialog' ).html( ' Error: ' + data.error.info + ' ' ).dialog( { title: 'Hey! Listen!', resizable: false, width: 400, modal: true, buttons: { 'Retry': function { $this.click; $( this ).dialog( 'destroy' ); $( '#error-dialog' ).remove; },							Cancel: function { $( this ).dialog( 'destroy' ); $( '#error-dialog' ).remove; return; }						}					} );				} );				return; }			$content.html( data.parse.text['*'] ); $this.text( hideText ); $body.removeClass( 'loading' ); $( 'body' ).css( 'cursor', 'auto' ); // Add Ajax compatible functions here window.mcw.animation; window.mcw.makeCollapsible; } ).fail( function( error ) { if ( $( '#error-dialog' ).length ) { return; }			mw.loader.using( 'jquery.ui.dialog', function {				$body.removeClass( 'loading' );				$( 'body' ).css( 'cursor', 'auto' );				$( '#netbar' ).after( ' ' );				if ( !error.responseText ){					$( '#error-dialog' ).html( ' Error: No response from the server ' );				} else {					$( '#error-dialog' ).html( ' Error: ' + error.responseText + ' ' );				}				$( '#error-dialog' ).dialog( { title: 'Hey! Listen!', resizable: false, width: 400, modal: true, buttons: { 'Retry': function { $this.click; $( this ).dialog( 'destroy' ); $( '#error-dialog' ).remove; },						Cancel: function { $( this ).dialog( 'destroy' ); $( '#error-dialog' ).remove; return; }					}				} );			} );		} );	} else if ( $this.text === showText ) {		$content.show;		$this.text( hideText );	} else {		$content.hide;		$this.text( showText );	} } );

/** * Replace part of ext.vector.collapsibleTabs.js (https://gerrit.wikimedia.org/r/gitweb?p=mediawiki/extensions/Vector.git;a=blob;f=modules/ext.vector.collapsibleTabs.js;hb=HEAD) * so it takes into account the padding and margins set on the tabs, * as well as the new size of the menu tab */ var rtl = $( 'body' ).is( '.rtl' ); $( '#p-views ul' ).unbind( 'beforeTabCollapse' ).bind( 'beforeTabCollapse', function {	if ( $( '#p-cactions' ).css( 'display' ) === 'none' ) {		$( '#p-cactions' )			.addClass( 'filledPortlet' ).removeClass( 'emptyPortlet' )			.find( 'h5' )				.css( 'width','1px' ).animate( { 'width':'37px' }, 390 );	} } ).collapsibleTabs( {	expandCondition: function ( eleWidth ) {		if ( rtl ) {			return ( $( '#right-navigation' ).position.left + $( '#right-navigation' ).width + 17 ) <						( $( '#left-navigation' ).position.left - eleWidth - 13 );		}		return ( $( '#left-navigation' ).position.left + $( '#left-navigation' ).width + 17 ) <					( $( '#right-navigation' ).position.left - eleWidth - 13 );	},	collapseCondition: function  {		if ( rtl ) {			return ( $( '#right-navigation' ).position.left + $( '#right-navigation' ).width + 17 ) >						( $( '#left-navigation' ).position.left ); }		return ( $( '#left-navigation' ).position.left + $( '#left-navigation' ).width + 17 ) > ( $( '#right-navigation' ).position.left ); } } );

/** * Fix searchbar suggestions box */ $( '.suggestions:last' ).addClass( 'searchbar' );

/** * Collapsible details for Template:History * * Allows version history to be split up into snapshots */ if ( $( '.history2' ).find( 'pre' ).length ) { var histExpandText = 'View snapshot history', histCollapseText = 'Hide snapshot history';

$( '.history2 th:first' ).append( ' [ ' + histExpandText + ' ] ' );

var histLink = $( '.toggleHistDetails .jslink' ); histLink.click( function {		if ( $( '.history2 .details' ).length ) {			$( '.history2 .overview' ).toggle;			$( '.history2 .details' ).toggle;		} else {			$( '.history2 tr' ).each( function { if ( !$( this ).find( 'pre' ).length || !$( this ).find( 'th' ).length ) { return true; }				var header = $( this ), row = header, text = header.find( '> td' ).html + ' ', rowspan = header.find( '> th' ).prop( 'rowspan' ); row.addClass( 'overview' ); if ( rowspan > 1 ) { for ( var i = 1; i < rowspan; i++ ) { row = row.next; if ( !row.length ) { break; }						row.addClass( 'overview' ); text += '\n ' + row.find( '> td' ).html + '  '; }				}				var versions = text.split( ' ' ), data = []; rowspan = 0; $.each( versions, function {					var parts = this.split( '' ), version = parts[0].replace( /\n/g, '' ), text = parts[1];					if ( !version || !text ) {						return true;					}					text = text.replace( / /g, ' ' );					if ( text.slice( text.lastIndexOf( ' ' ) ).indexOf( ' ' ) > -1 ) {						text = text.slice( 0, text.lastIndexOf( ' ' ) );					}					if ( text.slice( text.lastIndexOf( ' ' ) ).indexOf( ' ' ) < 0 ) {						text += ' ';					}					if ( version.match( /\d\dw\d\d\w/ ) ) {						version = '' + version + '';					} else {						version = '' + version + '</a>';					}					var rows;					if ( text.match( / /g ) ) {						rows = text.match( / /g ).length + 1; } else { rows = 1; }					rowspan += rows; data.push( '<th rowspan="' + rows + '">' + version + ' ' + text ); } );				var html = ' <th rowspan="' + rowspan + '">' + header.find( '> th' ).html + ' ' + data.join( ' ' );				$( ' ' ).find( 'td > ol' ).each( function { var text = $( this ).html; html = html.split( '<ol>' + text + '</ol>' ).join( '<ul>' + text + '</ul>' ); } );				row.after( html );			} ); $( '.history2 .overview' ).hide; }		if ( histLink.text === histExpandText) { histLink.text( histCollapseText ); } else { histLink.text( histExpandText ); }	} ); }

/** * Issue tracker loader */ if ( $( '#issue-list' ).length ) { var page = $( '#issue-list' ).data( 'name' ) || mw.config.get( 'wgPageName' ), amount = $( '#issue-list' ).data( 'num' ) || 20; if ( $.isArray( page ) ) { page = page.join( '" OR summary ~ "' ); }	var jql = encodeURIComponent( 'project in (MC, MCPE) AND resolution = Unresolved AND ( summary ~ "' + page + '" )' ); $.ajax( 		'https://mojang.atlassian.net/rest/api/latest/search?maxResults=' + amount + '&fields=summary&jql=' + jql	).done( function( search ) {		if ( !search.issues.length ) {			$( '#issue-list' ).text( 'No issues were found.' );			return false;		}

var compIssues = [], pocketIssues = []; $.each( search.issues, function {			if ( this.key.indexOf( 'MCPE' ) < 0 ) {				compIssues.push( '<li>[' + this.key + '</a>] - ' + this.fields.summary + '</li>' );			} else {				pocketIssues.push( '<li>[' + this.key + '</a>] - ' + this.fields.summary + '</li>' );			}		} ); var html = ''; if ( compIssues.length ) { html = ' Computer: <ul>' + compIssues.join( '\n' ) + '</ul>'; }		if ( pocketIssues.length ) { html += '\n Pocket Edition: <ul>' + pocketIssues.join( '\n' ) + '</ul>'; }		if ( search.total > amount ) { var extra = search.total - amount; html += '\n View ' + extra + ' more result'; if ( extra > 1 ) { html += 's'; }			html += '</a> '; }

$( '#issue-list' ).html( html ); } ); }

/** * Set unlicensed as the default license on file pages * * That way the file will be categorised so someone can find a license for the file */ if ( mw.config.get( 'wgPageName' ) === 'Special:Upload' && $( '#wpLicense' ).val === '' ) { $( '#wpLicense > option' ).filter( function {		// Have to select the license based on the text instead of the value,		// because "I'm not sure of this file's license" uses the same value		return $( this ).text.trim === 'This file is unlicensed';	} ).prop( 'selected', true ).change; }

/** * Fix missing toolbar images */ if ( $( '#toolbar' ).length ) { $( '#mw-editbutton-bold' )    .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/e/e2/Button_bold.png' ); $( '#mw-editbutton-italic' )  .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/1/1d/Button_italic.png' ); $( '#mw-editbutton-link' )    .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/c/c0/Button_link.png' ); $( '#mw-editbutton-extlink' ) .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/e/ec/Button_extlink.png' ); $( '#mw-editbutton-headline' ) .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/f/fb/Button_headline.png' ); $( '#mw-editbutton-image' )   .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/d/de/Button_image.png' ); $( '#mw-editbutton-media' )   .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/1/19/Button_media.png' ); $( '#mw-editbutton-nowiki' )  .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/8/82/Nowiki_icon.png' ); $( '#mw-editbutton-signature' ).prop( 'src', '//upload.wikimedia.org/wikipedia/commons/6/6d/Button_sig.png' ); $( '#mw-editbutton-hr' )      .prop( 'src', '//upload.wikimedia.org/wikipedia/commons/0/0d/Button_hr.png' ); }

} );